]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/brig/brigfrontend/brig-util.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / brig / brigfrontend / brig-util.cc
CommitLineData
5fd1486c 1/* brig-util.cc -- gccbrig utility functions
8d9254fc 2 Copyright (C) 2016-2020 Free Software Foundation, Inc.
5fd1486c
PJ
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. */
21
22#include <sstream>
23
24#include "stdint.h"
25#include "hsa-brig-format.h"
26#include "brig-util.h"
27#include "errors.h"
28#include "diagnostic-core.h"
dc03239c 29#include "print-tree.h"
5fd1486c 30
d4b7f2ee
PJ
31bool
32group_variable_offset_index::has_variable (const std::string &name) const
33{
34 varname_offset_table::const_iterator i = m_group_offsets.find (name);
35 return i != m_group_offsets.end ();
36}
37
38/* Adds a new group segment variable. */
39
40void
41group_variable_offset_index::add (const std::string &name, size_t size,
42 size_t alignment)
43{
44 size_t align_padding = m_next_group_offset % alignment == 0 ?
45 0 : (alignment - m_next_group_offset % alignment);
46 m_next_group_offset += align_padding;
47 m_group_offsets[name] = m_next_group_offset;
48 m_next_group_offset += size;
49}
50
51size_t
52group_variable_offset_index::segment_offset (const std::string &name) const
53{
54 varname_offset_table::const_iterator i = m_group_offsets.find (name);
55 gcc_assert (i != m_group_offsets.end ());
56 return (*i).second;
57}
58
5fd1486c
PJ
59/* Return true if operand number OPNUM of instruction with OPCODE is an output.
60 False if it is an input. Some code reused from Martin Jambor's gcc-hsa
61 tree. */
62
63bool
64gccbrig_hsa_opcode_op_output_p (BrigOpcode16_t opcode, int opnum)
65{
66 switch (opcode)
67 {
68 case BRIG_OPCODE_BR:
69 case BRIG_OPCODE_SBR:
70 case BRIG_OPCODE_CBR:
71 case BRIG_OPCODE_ST:
72 case BRIG_OPCODE_ATOMICNORET:
73 case BRIG_OPCODE_SIGNALNORET:
74 case BRIG_OPCODE_INITFBAR:
75 case BRIG_OPCODE_JOINFBAR:
76 case BRIG_OPCODE_WAITFBAR:
77 case BRIG_OPCODE_ARRIVEFBAR:
78 case BRIG_OPCODE_LEAVEFBAR:
79 case BRIG_OPCODE_RELEASEFBAR:
80 case BRIG_OPCODE_DEBUGTRAP:
81 return false;
82 default:
83 return opnum == 0;
84 }
85}
86
87unsigned
88gccbrig_hsa_type_bit_size (BrigType16_t t)
89{
90
91 unsigned pack_type = t & ~BRIG_TYPE_BASE_MASK;
92
93 if (pack_type == BRIG_TYPE_PACK_32)
94 return 32;
95 else if (pack_type == BRIG_TYPE_PACK_64)
96 return 64;
97 else if (pack_type == BRIG_TYPE_PACK_128)
98 return 128;
99
100 switch (t)
101 {
102 case BRIG_TYPE_NONE:
103 return 0;
104
105 case BRIG_TYPE_B1:
106 return 1;
107
108 case BRIG_TYPE_U8:
109 case BRIG_TYPE_S8:
110 case BRIG_TYPE_B8:
111 return 8;
112
113 case BRIG_TYPE_U16:
114 case BRIG_TYPE_S16:
115 case BRIG_TYPE_B16:
116 case BRIG_TYPE_F16:
117 return 16;
118
119 case BRIG_TYPE_U32:
120 case BRIG_TYPE_S32:
121 case BRIG_TYPE_B32:
122 case BRIG_TYPE_F32:
123 case BRIG_TYPE_U8X4:
124 case BRIG_TYPE_U16X2:
125 case BRIG_TYPE_S8X4:
126 case BRIG_TYPE_S16X2:
127 case BRIG_TYPE_F16X2:
128 case BRIG_TYPE_SIG32:
129 return 32;
130
131 case BRIG_TYPE_U64:
132 case BRIG_TYPE_S64:
133 case BRIG_TYPE_F64:
134 case BRIG_TYPE_B64:
135 case BRIG_TYPE_U8X8:
136 case BRIG_TYPE_U16X4:
137 case BRIG_TYPE_U32X2:
138 case BRIG_TYPE_S8X8:
139 case BRIG_TYPE_S16X4:
140 case BRIG_TYPE_S32X2:
141 case BRIG_TYPE_F16X4:
142 case BRIG_TYPE_F32X2:
143 case BRIG_TYPE_SIG64:
144 return 64;
145
146 case BRIG_TYPE_B128:
147 case BRIG_TYPE_U8X16:
148 case BRIG_TYPE_U16X8:
149 case BRIG_TYPE_U32X4:
150 case BRIG_TYPE_U64X2:
151 case BRIG_TYPE_S8X16:
152 case BRIG_TYPE_S16X8:
153 case BRIG_TYPE_S32X4:
154 case BRIG_TYPE_S64X2:
155 case BRIG_TYPE_F16X8:
156 case BRIG_TYPE_F32X4:
157 case BRIG_TYPE_F64X2:
158 return 128;
159
160 default:
161 printf ("HMM %d %x\n", t, t);
162 gcc_unreachable ();
163 }
164}
165
166/* gcc-hsa borrowed code ENDS. */
167
168uint64_t
169gccbrig_to_uint64_t (const BrigUInt64 &brig_type)
170{
171 return (uint64_t (brig_type.hi) << 32) | uint64_t (brig_type.lo);
172}
173
174int
175gccbrig_reg_size (const BrigOperandRegister *brig_reg)
176{
177 switch (brig_reg->regKind)
178 {
179 case BRIG_REGISTER_KIND_CONTROL:
180 return 1;
181 case BRIG_REGISTER_KIND_SINGLE:
182 return 32;
183 case BRIG_REGISTER_KIND_DOUBLE:
184 return 64;
185 case BRIG_REGISTER_KIND_QUAD:
186 return 128;
187 default:
188 gcc_unreachable ();
189 break;
190 }
191}
192
193std::string
194gccbrig_reg_name (const BrigOperandRegister *reg)
195{
196 std::ostringstream strstr;
197 switch (reg->regKind)
198 {
199 case BRIG_REGISTER_KIND_CONTROL:
200 strstr << 'c';
201 break;
202 case BRIG_REGISTER_KIND_SINGLE:
203 strstr << 's';
204 break;
205 case BRIG_REGISTER_KIND_DOUBLE:
206 strstr << 'd';
207 break;
208 case BRIG_REGISTER_KIND_QUAD:
209 strstr << 'q';
210 break;
211 default:
212 gcc_unreachable ();
213 return "";
214 }
215 strstr << reg->regNum;
216 return strstr.str ();
217}
218
219std::string
220gccbrig_type_name (BrigType16_t type)
221{
222 switch (type)
223 {
224 case BRIG_TYPE_U8:
225 return "u8";
226 case BRIG_TYPE_U16:
227 return "u16";
228 case BRIG_TYPE_U32:
229 return "u32";
230 case BRIG_TYPE_U64:
231 return "u64";
232 case BRIG_TYPE_S8:
233 return "s8";
234 case BRIG_TYPE_S16:
235 return "s16";
236 case BRIG_TYPE_S32:
237 return "s32";
238 case BRIG_TYPE_S64:
239 return "s64";
240 default:
241 gcc_unreachable ();
242 break;
243 }
244}
245
246std::string
247gccbrig_segment_name (BrigSegment8_t segment)
248{
249 if (segment == BRIG_SEGMENT_GLOBAL)
250 return "global";
251 else if (segment == BRIG_SEGMENT_GROUP)
252 return "group";
253 else if (segment == BRIG_SEGMENT_PRIVATE)
254 return "private";
255 else
256 gcc_unreachable ();
257}
258
259bool
260gccbrig_is_float_type (BrigType16_t type)
261{
262 return (type == BRIG_TYPE_F32 || type == BRIG_TYPE_F64
263 || type == BRIG_TYPE_F16);
264}
265
266BrigType16_t
267gccbrig_tree_type_to_hsa_type (tree tree_type)
268{
269 if (INTEGRAL_TYPE_P (tree_type))
270 {
271 if (TYPE_UNSIGNED (tree_type))
272 {
273 switch (int_size_in_bytes (tree_type))
274 {
275 case 1:
276 return BRIG_TYPE_U8;
277 case 2:
278 return BRIG_TYPE_U16;
279 case 4:
280 return BRIG_TYPE_U32;
281 case 8:
282 return BRIG_TYPE_U64;
283 default:
284 break;
285 }
286 }
287 else
288 {
289 switch (int_size_in_bytes (tree_type))
290 {
291 case 1:
292 return BRIG_TYPE_S8;
293 case 2:
294 return BRIG_TYPE_S16;
295 case 4:
296 return BRIG_TYPE_S32;
297 case 8:
298 return BRIG_TYPE_S64;
299 default:
300 break;
301 }
302 }
303 }
304 else if (VECTOR_TYPE_P (tree_type))
305 {
306 tree element_type = TREE_TYPE (tree_type);
307 size_t element_size = int_size_in_bytes (element_type) * 8;
308 BrigType16_t brig_element_type;
309 switch (element_size)
310 {
311 case 8:
312 brig_element_type
313 = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U8 : BRIG_TYPE_S8;
314 break;
315 case 16:
316 brig_element_type
317 = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U16 : BRIG_TYPE_S16;
318 break;
319 case 32:
320 brig_element_type
321 = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U32 : BRIG_TYPE_S32;
322 break;
323 case 64:
324 brig_element_type
325 = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U64 : BRIG_TYPE_S64;
326 break;
327 default:
328 gcc_unreachable ();
329 }
330
331 BrigType16_t pack_type;
332 switch (int_size_in_bytes (tree_type) * 8)
333 {
334 case 32:
335 pack_type = BRIG_TYPE_PACK_32;
336 break;
337 case 64:
338 pack_type = BRIG_TYPE_PACK_64;
339 break;
340 case 128:
341 pack_type = BRIG_TYPE_PACK_128;
342 break;
343 default:
344 gcc_unreachable ();
345 }
346 return brig_element_type | pack_type;
347 }
348 gcc_unreachable ();
349}
350
351/* Returns true in case the operation is a "bit level" operation,
352 that is, not having operand type depending semantical differences. */
353
354bool
355gccbrig_is_bit_operation (BrigOpcode16_t opcode)
356{
357 return opcode == BRIG_OPCODE_CMOV || opcode == BRIG_OPCODE_SHUFFLE
358 || opcode == BRIG_OPCODE_UNPACK || opcode == BRIG_OPCODE_UNPACKLO
359 || opcode == BRIG_OPCODE_UNPACKHI || opcode == BRIG_OPCODE_ST
360 || opcode == BRIG_OPCODE_PACK;
361}
362
363/* The program scope definition can be left external within the
364 kernel binary which means it must be defined by the host via
365 HSA runtime. For these we have special treatment:
366 Create additional pointer indirection when accessing the variable
367 value from kernel code through a generated pointer
368 __gccbrig_ptr_variable_name. The pointer value then can be set either
369 within the kernel binary (in case of a later linked in definition)
370 or from the host. */
371
372bool
373gccbrig_might_be_host_defined_var_p (const BrigDirectiveVariable *brigVar)
374{
375 bool is_definition = brigVar->modifier & BRIG_VARIABLE_DEFINITION;
376 return (brigVar->segment == BRIG_SEGMENT_GLOBAL
377 || brigVar->segment == BRIG_SEGMENT_READONLY) && !is_definition
378 && brigVar->linkage == BRIG_LINKAGE_PROGRAM
379 && (brigVar->allocation == BRIG_ALLOCATION_PROGRAM
380 || brigVar->allocation == BRIG_ALLOCATION_AGENT);
381}
382
383/* Produce a GENERIC type for the given HSA/BRIG type. Returns the element
384 type in case of vector instructions. */
385
386tree
387gccbrig_tree_type_for_hsa_type (BrigType16_t brig_type)
388{
389 tree tree_type = NULL_TREE;
390
391 if (hsa_type_packed_p (brig_type))
392 {
393 /* The element type is encoded in the bottom 5 bits. */
394 BrigType16_t inner_brig_type = brig_type & BRIG_TYPE_BASE_MASK;
395
396 unsigned full_size = gccbrig_hsa_type_bit_size (brig_type);
397
398 if (inner_brig_type == BRIG_TYPE_F16)
399 return build_vector_type (gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16),
400 full_size / 16);
401
402 tree inner_type = gccbrig_tree_type_for_hsa_type (inner_brig_type);
403
404 unsigned inner_size = gccbrig_hsa_type_bit_size (inner_brig_type);
405 unsigned nunits = full_size / inner_size;
406 tree_type = build_vector_type (inner_type, nunits);
407 }
408 else
409 {
410 switch (brig_type)
411 {
412 case BRIG_TYPE_NONE:
413 tree_type = void_type_node;
414 break;
415 case BRIG_TYPE_B1:
416 tree_type = boolean_type_node;
417 break;
418 case BRIG_TYPE_S8:
419 case BRIG_TYPE_S16:
420 case BRIG_TYPE_S32:
421 case BRIG_TYPE_S64:
422 /* Ensure a fixed width integer. */
423 tree_type
424 = build_nonstandard_integer_type
425 (gccbrig_hsa_type_bit_size (brig_type), false);
426 break;
427 case BRIG_TYPE_U8:
428 return unsigned_char_type_node;
429 case BRIG_TYPE_U16:
430 case BRIG_TYPE_U32:
431 case BRIG_TYPE_U64:
432 case BRIG_TYPE_B8: /* Handle bit vectors as unsigned ints. */
433 case BRIG_TYPE_B16:
434 case BRIG_TYPE_B32:
435 case BRIG_TYPE_B64:
436 case BRIG_TYPE_B128:
437 case BRIG_TYPE_SIG32: /* Handle signals as integers for now. */
438 case BRIG_TYPE_SIG64:
439 tree_type = build_nonstandard_integer_type
440 (gccbrig_hsa_type_bit_size (brig_type), true);
441 break;
442 case BRIG_TYPE_F16:
443 tree_type = uint16_type_node;
444 break;
445 case BRIG_TYPE_F32:
446 /* TODO: make sure that the alignment of the float are at least as
447 strict than mandated by HSA, and conform to IEEE (like mandated
448 by HSA). */
449 tree_type = float_type_node;
450 break;
451 case BRIG_TYPE_F64:
452 tree_type = double_type_node;
453 break;
454 case BRIG_TYPE_SAMP:
455 case BRIG_TYPE_ROIMG:
456 case BRIG_TYPE_WOIMG:
457 case BRIG_TYPE_RWIMG:
458 {
459 /* Handle images and samplers as target-specific blobs of data
460 that should be allocated earlier on from the runtime side.
461 Create a void* that should be initialized to point to the blobs
462 by the kernel launcher. Images and samplers are accessed
463 via builtins that take void* as the reference. TODO: who and
464 how these arrays should be initialized? */
465 tree void_ptr = build_pointer_type (void_type_node);
466 return void_ptr;
467 }
468 default:
469 gcc_unreachable ();
470 break;
471 }
472 }
473
474 /* Drop const qualifiers. */
475 return tree_type;
476}
dc03239c
HL
477
478/* Calculates numeric identifier for the HSA register REG.
479
480 Returned value is bound to [0, BRIG_2_TREE_HSAIL_TOTAL_REG_COUNT]. */
481
482size_t
483gccbrig_hsa_reg_id (const BrigOperandRegister &reg)
484{
485 size_t offset = reg.regNum;
486 switch (reg.regKind)
487 {
488 case BRIG_REGISTER_KIND_QUAD:
489 offset
490 += BRIG_2_TREE_HSAIL_D_REG_COUNT + BRIG_2_TREE_HSAIL_S_REG_COUNT
491 + BRIG_2_TREE_HSAIL_C_REG_COUNT;
492 break;
493 case BRIG_REGISTER_KIND_DOUBLE:
494 offset += BRIG_2_TREE_HSAIL_S_REG_COUNT + BRIG_2_TREE_HSAIL_C_REG_COUNT;
495 break;
496 case BRIG_REGISTER_KIND_SINGLE:
497 offset += BRIG_2_TREE_HSAIL_C_REG_COUNT;
498 case BRIG_REGISTER_KIND_CONTROL:
499 break;
500 default:
501 gcc_unreachable ();
502 break;
503 }
504 return offset;
505}
506
507std::string
610f66a3 508gccbrig_hsa_reg_name_from_id (size_t reg_id)
dc03239c
HL
509{
510 char reg_name[32];
610f66a3 511 long unsigned int reg_hash = (long unsigned int) reg_id;
dc03239c
HL
512 if (reg_hash < BRIG_2_TREE_HSAIL_C_REG_COUNT)
513 {
514 sprintf (reg_name, "$c%lu", reg_hash);
515 return reg_name;
516 }
517
518 reg_hash -= BRIG_2_TREE_HSAIL_C_REG_COUNT;
519 if (reg_hash < BRIG_2_TREE_HSAIL_S_REG_COUNT)
520 {
521 sprintf (reg_name, "$s%lu", reg_hash);
522 return reg_name;
523 }
524
525 reg_hash -= BRIG_2_TREE_HSAIL_S_REG_COUNT;
526 if (reg_hash < BRIG_2_TREE_HSAIL_D_REG_COUNT)
527 {
528 sprintf (reg_name, "$d%lu", reg_hash);
529 return reg_name;
530 }
531
532 reg_hash -= BRIG_2_TREE_HSAIL_D_REG_COUNT;
533 if (reg_hash < BRIG_2_TREE_HSAIL_Q_REG_COUNT)
534 {
535 sprintf (reg_name, "$q%lu", reg_hash);
536 return reg_name;
537 }
538
539 gcc_unreachable ();
540 return "$??";
541}
542
543/* Prints statistics of register usage to stdout. */
544
545void
546gccbrig_print_reg_use_info (FILE *dump, const regs_use_index &info)
547{
548 regs_use_index::const_iterator begin_it = info.begin ();
549 regs_use_index::const_iterator end_it = info.end ();
550 for (regs_use_index::const_iterator it = begin_it; it != end_it; it++)
551 {
552 std::string hsa_reg = gccbrig_hsa_reg_name_from_id (it->first);
553 printf ("%s:\n", hsa_reg.c_str ());
554 const reg_use_info &info = it->second;
555 typedef std::vector<std::pair<tree, size_t> >::const_iterator reg_use_it;
556 reg_use_it begin_it2 = info.m_type_refs.begin ();
557 reg_use_it end_it2 = info.m_type_refs.end ();
558 for (reg_use_it it2 = begin_it2; it2 != end_it2; it2++)
559 {
610f66a3 560 fprintf (dump, "(%lu) ", (long unsigned int) it2->second);
dc03239c
HL
561 print_node_brief (dump, "", it2->first, 0);
562 fprintf (dump, "\n");
563 }
564 }
565}