]>
Commit | Line | Data |
---|---|---|
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 | ||
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 <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 |
31 | bool |
32 | group_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 | ||
40 | void | |
41 | group_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 | ||
51 | size_t | |
52 | group_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 | ||
63 | bool | |
64 | gccbrig_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 | ||
87 | unsigned | |
88 | gccbrig_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 | ||
168 | uint64_t | |
169 | gccbrig_to_uint64_t (const BrigUInt64 &brig_type) | |
170 | { | |
171 | return (uint64_t (brig_type.hi) << 32) | uint64_t (brig_type.lo); | |
172 | } | |
173 | ||
174 | int | |
175 | gccbrig_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 | ||
193 | std::string | |
194 | gccbrig_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 | ||
219 | std::string | |
220 | gccbrig_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 | ||
246 | std::string | |
247 | gccbrig_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 | ||
259 | bool | |
260 | gccbrig_is_float_type (BrigType16_t type) | |
261 | { | |
262 | return (type == BRIG_TYPE_F32 || type == BRIG_TYPE_F64 | |
263 | || type == BRIG_TYPE_F16); | |
264 | } | |
265 | ||
266 | BrigType16_t | |
267 | gccbrig_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 | ||
354 | bool | |
355 | gccbrig_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 | ||
372 | bool | |
373 | gccbrig_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 | ||
386 | tree | |
387 | gccbrig_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 | ||
482 | size_t | |
483 | gccbrig_hsa_reg_id (const BrigOperandRegister ®) | |
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 | ||
507 | std::string | |
610f66a3 | 508 | gccbrig_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 | ||
545 | void | |
546 | gccbrig_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 | } |