]>
Commit | Line | Data |
---|---|---|
5fd1486c | 1 | /* brig-util.cc -- gccbrig utility functions |
68edb9ba | 2 | Copyright (C) 2016-2017 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" | |
29 | ||
d4b7f2ee PJ |
30 | bool |
31 | group_variable_offset_index::has_variable (const std::string &name) const | |
32 | { | |
33 | varname_offset_table::const_iterator i = m_group_offsets.find (name); | |
34 | return i != m_group_offsets.end (); | |
35 | } | |
36 | ||
37 | /* Adds a new group segment variable. */ | |
38 | ||
39 | void | |
40 | group_variable_offset_index::add (const std::string &name, size_t size, | |
41 | size_t alignment) | |
42 | { | |
43 | size_t align_padding = m_next_group_offset % alignment == 0 ? | |
44 | 0 : (alignment - m_next_group_offset % alignment); | |
45 | m_next_group_offset += align_padding; | |
46 | m_group_offsets[name] = m_next_group_offset; | |
47 | m_next_group_offset += size; | |
48 | } | |
49 | ||
50 | size_t | |
51 | group_variable_offset_index::segment_offset (const std::string &name) const | |
52 | { | |
53 | varname_offset_table::const_iterator i = m_group_offsets.find (name); | |
54 | gcc_assert (i != m_group_offsets.end ()); | |
55 | return (*i).second; | |
56 | } | |
57 | ||
5fd1486c PJ |
58 | /* Return true if operand number OPNUM of instruction with OPCODE is an output. |
59 | False if it is an input. Some code reused from Martin Jambor's gcc-hsa | |
60 | tree. */ | |
61 | ||
62 | bool | |
63 | gccbrig_hsa_opcode_op_output_p (BrigOpcode16_t opcode, int opnum) | |
64 | { | |
65 | switch (opcode) | |
66 | { | |
67 | case BRIG_OPCODE_BR: | |
68 | case BRIG_OPCODE_SBR: | |
69 | case BRIG_OPCODE_CBR: | |
70 | case BRIG_OPCODE_ST: | |
71 | case BRIG_OPCODE_ATOMICNORET: | |
72 | case BRIG_OPCODE_SIGNALNORET: | |
73 | case BRIG_OPCODE_INITFBAR: | |
74 | case BRIG_OPCODE_JOINFBAR: | |
75 | case BRIG_OPCODE_WAITFBAR: | |
76 | case BRIG_OPCODE_ARRIVEFBAR: | |
77 | case BRIG_OPCODE_LEAVEFBAR: | |
78 | case BRIG_OPCODE_RELEASEFBAR: | |
79 | case BRIG_OPCODE_DEBUGTRAP: | |
80 | return false; | |
81 | default: | |
82 | return opnum == 0; | |
83 | } | |
84 | } | |
85 | ||
86 | unsigned | |
87 | gccbrig_hsa_type_bit_size (BrigType16_t t) | |
88 | { | |
89 | ||
90 | unsigned pack_type = t & ~BRIG_TYPE_BASE_MASK; | |
91 | ||
92 | if (pack_type == BRIG_TYPE_PACK_32) | |
93 | return 32; | |
94 | else if (pack_type == BRIG_TYPE_PACK_64) | |
95 | return 64; | |
96 | else if (pack_type == BRIG_TYPE_PACK_128) | |
97 | return 128; | |
98 | ||
99 | switch (t) | |
100 | { | |
101 | case BRIG_TYPE_NONE: | |
102 | return 0; | |
103 | ||
104 | case BRIG_TYPE_B1: | |
105 | return 1; | |
106 | ||
107 | case BRIG_TYPE_U8: | |
108 | case BRIG_TYPE_S8: | |
109 | case BRIG_TYPE_B8: | |
110 | return 8; | |
111 | ||
112 | case BRIG_TYPE_U16: | |
113 | case BRIG_TYPE_S16: | |
114 | case BRIG_TYPE_B16: | |
115 | case BRIG_TYPE_F16: | |
116 | return 16; | |
117 | ||
118 | case BRIG_TYPE_U32: | |
119 | case BRIG_TYPE_S32: | |
120 | case BRIG_TYPE_B32: | |
121 | case BRIG_TYPE_F32: | |
122 | case BRIG_TYPE_U8X4: | |
123 | case BRIG_TYPE_U16X2: | |
124 | case BRIG_TYPE_S8X4: | |
125 | case BRIG_TYPE_S16X2: | |
126 | case BRIG_TYPE_F16X2: | |
127 | case BRIG_TYPE_SIG32: | |
128 | return 32; | |
129 | ||
130 | case BRIG_TYPE_U64: | |
131 | case BRIG_TYPE_S64: | |
132 | case BRIG_TYPE_F64: | |
133 | case BRIG_TYPE_B64: | |
134 | case BRIG_TYPE_U8X8: | |
135 | case BRIG_TYPE_U16X4: | |
136 | case BRIG_TYPE_U32X2: | |
137 | case BRIG_TYPE_S8X8: | |
138 | case BRIG_TYPE_S16X4: | |
139 | case BRIG_TYPE_S32X2: | |
140 | case BRIG_TYPE_F16X4: | |
141 | case BRIG_TYPE_F32X2: | |
142 | case BRIG_TYPE_SIG64: | |
143 | return 64; | |
144 | ||
145 | case BRIG_TYPE_B128: | |
146 | case BRIG_TYPE_U8X16: | |
147 | case BRIG_TYPE_U16X8: | |
148 | case BRIG_TYPE_U32X4: | |
149 | case BRIG_TYPE_U64X2: | |
150 | case BRIG_TYPE_S8X16: | |
151 | case BRIG_TYPE_S16X8: | |
152 | case BRIG_TYPE_S32X4: | |
153 | case BRIG_TYPE_S64X2: | |
154 | case BRIG_TYPE_F16X8: | |
155 | case BRIG_TYPE_F32X4: | |
156 | case BRIG_TYPE_F64X2: | |
157 | return 128; | |
158 | ||
159 | default: | |
160 | printf ("HMM %d %x\n", t, t); | |
161 | gcc_unreachable (); | |
162 | } | |
163 | } | |
164 | ||
165 | /* gcc-hsa borrowed code ENDS. */ | |
166 | ||
167 | uint64_t | |
168 | gccbrig_to_uint64_t (const BrigUInt64 &brig_type) | |
169 | { | |
170 | return (uint64_t (brig_type.hi) << 32) | uint64_t (brig_type.lo); | |
171 | } | |
172 | ||
173 | int | |
174 | gccbrig_reg_size (const BrigOperandRegister *brig_reg) | |
175 | { | |
176 | switch (brig_reg->regKind) | |
177 | { | |
178 | case BRIG_REGISTER_KIND_CONTROL: | |
179 | return 1; | |
180 | case BRIG_REGISTER_KIND_SINGLE: | |
181 | return 32; | |
182 | case BRIG_REGISTER_KIND_DOUBLE: | |
183 | return 64; | |
184 | case BRIG_REGISTER_KIND_QUAD: | |
185 | return 128; | |
186 | default: | |
187 | gcc_unreachable (); | |
188 | break; | |
189 | } | |
190 | } | |
191 | ||
192 | std::string | |
193 | gccbrig_reg_name (const BrigOperandRegister *reg) | |
194 | { | |
195 | std::ostringstream strstr; | |
196 | switch (reg->regKind) | |
197 | { | |
198 | case BRIG_REGISTER_KIND_CONTROL: | |
199 | strstr << 'c'; | |
200 | break; | |
201 | case BRIG_REGISTER_KIND_SINGLE: | |
202 | strstr << 's'; | |
203 | break; | |
204 | case BRIG_REGISTER_KIND_DOUBLE: | |
205 | strstr << 'd'; | |
206 | break; | |
207 | case BRIG_REGISTER_KIND_QUAD: | |
208 | strstr << 'q'; | |
209 | break; | |
210 | default: | |
211 | gcc_unreachable (); | |
212 | return ""; | |
213 | } | |
214 | strstr << reg->regNum; | |
215 | return strstr.str (); | |
216 | } | |
217 | ||
218 | std::string | |
219 | gccbrig_type_name (BrigType16_t type) | |
220 | { | |
221 | switch (type) | |
222 | { | |
223 | case BRIG_TYPE_U8: | |
224 | return "u8"; | |
225 | case BRIG_TYPE_U16: | |
226 | return "u16"; | |
227 | case BRIG_TYPE_U32: | |
228 | return "u32"; | |
229 | case BRIG_TYPE_U64: | |
230 | return "u64"; | |
231 | case BRIG_TYPE_S8: | |
232 | return "s8"; | |
233 | case BRIG_TYPE_S16: | |
234 | return "s16"; | |
235 | case BRIG_TYPE_S32: | |
236 | return "s32"; | |
237 | case BRIG_TYPE_S64: | |
238 | return "s64"; | |
239 | default: | |
240 | gcc_unreachable (); | |
241 | break; | |
242 | } | |
243 | } | |
244 | ||
245 | std::string | |
246 | gccbrig_segment_name (BrigSegment8_t segment) | |
247 | { | |
248 | if (segment == BRIG_SEGMENT_GLOBAL) | |
249 | return "global"; | |
250 | else if (segment == BRIG_SEGMENT_GROUP) | |
251 | return "group"; | |
252 | else if (segment == BRIG_SEGMENT_PRIVATE) | |
253 | return "private"; | |
254 | else | |
255 | gcc_unreachable (); | |
256 | } | |
257 | ||
258 | bool | |
259 | gccbrig_is_float_type (BrigType16_t type) | |
260 | { | |
261 | return (type == BRIG_TYPE_F32 || type == BRIG_TYPE_F64 | |
262 | || type == BRIG_TYPE_F16); | |
263 | } | |
264 | ||
265 | BrigType16_t | |
266 | gccbrig_tree_type_to_hsa_type (tree tree_type) | |
267 | { | |
268 | if (INTEGRAL_TYPE_P (tree_type)) | |
269 | { | |
270 | if (TYPE_UNSIGNED (tree_type)) | |
271 | { | |
272 | switch (int_size_in_bytes (tree_type)) | |
273 | { | |
274 | case 1: | |
275 | return BRIG_TYPE_U8; | |
276 | case 2: | |
277 | return BRIG_TYPE_U16; | |
278 | case 4: | |
279 | return BRIG_TYPE_U32; | |
280 | case 8: | |
281 | return BRIG_TYPE_U64; | |
282 | default: | |
283 | break; | |
284 | } | |
285 | } | |
286 | else | |
287 | { | |
288 | switch (int_size_in_bytes (tree_type)) | |
289 | { | |
290 | case 1: | |
291 | return BRIG_TYPE_S8; | |
292 | case 2: | |
293 | return BRIG_TYPE_S16; | |
294 | case 4: | |
295 | return BRIG_TYPE_S32; | |
296 | case 8: | |
297 | return BRIG_TYPE_S64; | |
298 | default: | |
299 | break; | |
300 | } | |
301 | } | |
302 | } | |
303 | else if (VECTOR_TYPE_P (tree_type)) | |
304 | { | |
305 | tree element_type = TREE_TYPE (tree_type); | |
306 | size_t element_size = int_size_in_bytes (element_type) * 8; | |
307 | BrigType16_t brig_element_type; | |
308 | switch (element_size) | |
309 | { | |
310 | case 8: | |
311 | brig_element_type | |
312 | = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U8 : BRIG_TYPE_S8; | |
313 | break; | |
314 | case 16: | |
315 | brig_element_type | |
316 | = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U16 : BRIG_TYPE_S16; | |
317 | break; | |
318 | case 32: | |
319 | brig_element_type | |
320 | = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U32 : BRIG_TYPE_S32; | |
321 | break; | |
322 | case 64: | |
323 | brig_element_type | |
324 | = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U64 : BRIG_TYPE_S64; | |
325 | break; | |
326 | default: | |
327 | gcc_unreachable (); | |
328 | } | |
329 | ||
330 | BrigType16_t pack_type; | |
331 | switch (int_size_in_bytes (tree_type) * 8) | |
332 | { | |
333 | case 32: | |
334 | pack_type = BRIG_TYPE_PACK_32; | |
335 | break; | |
336 | case 64: | |
337 | pack_type = BRIG_TYPE_PACK_64; | |
338 | break; | |
339 | case 128: | |
340 | pack_type = BRIG_TYPE_PACK_128; | |
341 | break; | |
342 | default: | |
343 | gcc_unreachable (); | |
344 | } | |
345 | return brig_element_type | pack_type; | |
346 | } | |
347 | gcc_unreachable (); | |
348 | } | |
349 | ||
350 | /* Returns true in case the operation is a "bit level" operation, | |
351 | that is, not having operand type depending semantical differences. */ | |
352 | ||
353 | bool | |
354 | gccbrig_is_bit_operation (BrigOpcode16_t opcode) | |
355 | { | |
356 | return opcode == BRIG_OPCODE_CMOV || opcode == BRIG_OPCODE_SHUFFLE | |
357 | || opcode == BRIG_OPCODE_UNPACK || opcode == BRIG_OPCODE_UNPACKLO | |
358 | || opcode == BRIG_OPCODE_UNPACKHI || opcode == BRIG_OPCODE_ST | |
359 | || opcode == BRIG_OPCODE_PACK; | |
360 | } | |
361 | ||
362 | /* The program scope definition can be left external within the | |
363 | kernel binary which means it must be defined by the host via | |
364 | HSA runtime. For these we have special treatment: | |
365 | Create additional pointer indirection when accessing the variable | |
366 | value from kernel code through a generated pointer | |
367 | __gccbrig_ptr_variable_name. The pointer value then can be set either | |
368 | within the kernel binary (in case of a later linked in definition) | |
369 | or from the host. */ | |
370 | ||
371 | bool | |
372 | gccbrig_might_be_host_defined_var_p (const BrigDirectiveVariable *brigVar) | |
373 | { | |
374 | bool is_definition = brigVar->modifier & BRIG_VARIABLE_DEFINITION; | |
375 | return (brigVar->segment == BRIG_SEGMENT_GLOBAL | |
376 | || brigVar->segment == BRIG_SEGMENT_READONLY) && !is_definition | |
377 | && brigVar->linkage == BRIG_LINKAGE_PROGRAM | |
378 | && (brigVar->allocation == BRIG_ALLOCATION_PROGRAM | |
379 | || brigVar->allocation == BRIG_ALLOCATION_AGENT); | |
380 | } | |
381 | ||
382 | /* Produce a GENERIC type for the given HSA/BRIG type. Returns the element | |
383 | type in case of vector instructions. */ | |
384 | ||
385 | tree | |
386 | gccbrig_tree_type_for_hsa_type (BrigType16_t brig_type) | |
387 | { | |
388 | tree tree_type = NULL_TREE; | |
389 | ||
390 | if (hsa_type_packed_p (brig_type)) | |
391 | { | |
392 | /* The element type is encoded in the bottom 5 bits. */ | |
393 | BrigType16_t inner_brig_type = brig_type & BRIG_TYPE_BASE_MASK; | |
394 | ||
395 | unsigned full_size = gccbrig_hsa_type_bit_size (brig_type); | |
396 | ||
397 | if (inner_brig_type == BRIG_TYPE_F16) | |
398 | return build_vector_type (gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16), | |
399 | full_size / 16); | |
400 | ||
401 | tree inner_type = gccbrig_tree_type_for_hsa_type (inner_brig_type); | |
402 | ||
403 | unsigned inner_size = gccbrig_hsa_type_bit_size (inner_brig_type); | |
404 | unsigned nunits = full_size / inner_size; | |
405 | tree_type = build_vector_type (inner_type, nunits); | |
406 | } | |
407 | else | |
408 | { | |
409 | switch (brig_type) | |
410 | { | |
411 | case BRIG_TYPE_NONE: | |
412 | tree_type = void_type_node; | |
413 | break; | |
414 | case BRIG_TYPE_B1: | |
415 | tree_type = boolean_type_node; | |
416 | break; | |
417 | case BRIG_TYPE_S8: | |
418 | case BRIG_TYPE_S16: | |
419 | case BRIG_TYPE_S32: | |
420 | case BRIG_TYPE_S64: | |
421 | /* Ensure a fixed width integer. */ | |
422 | tree_type | |
423 | = build_nonstandard_integer_type | |
424 | (gccbrig_hsa_type_bit_size (brig_type), false); | |
425 | break; | |
426 | case BRIG_TYPE_U8: | |
427 | return unsigned_char_type_node; | |
428 | case BRIG_TYPE_U16: | |
429 | case BRIG_TYPE_U32: | |
430 | case BRIG_TYPE_U64: | |
431 | case BRIG_TYPE_B8: /* Handle bit vectors as unsigned ints. */ | |
432 | case BRIG_TYPE_B16: | |
433 | case BRIG_TYPE_B32: | |
434 | case BRIG_TYPE_B64: | |
435 | case BRIG_TYPE_B128: | |
436 | case BRIG_TYPE_SIG32: /* Handle signals as integers for now. */ | |
437 | case BRIG_TYPE_SIG64: | |
438 | tree_type = build_nonstandard_integer_type | |
439 | (gccbrig_hsa_type_bit_size (brig_type), true); | |
440 | break; | |
441 | case BRIG_TYPE_F16: | |
442 | tree_type = uint16_type_node; | |
443 | break; | |
444 | case BRIG_TYPE_F32: | |
445 | /* TODO: make sure that the alignment of the float are at least as | |
446 | strict than mandated by HSA, and conform to IEEE (like mandated | |
447 | by HSA). */ | |
448 | tree_type = float_type_node; | |
449 | break; | |
450 | case BRIG_TYPE_F64: | |
451 | tree_type = double_type_node; | |
452 | break; | |
453 | case BRIG_TYPE_SAMP: | |
454 | case BRIG_TYPE_ROIMG: | |
455 | case BRIG_TYPE_WOIMG: | |
456 | case BRIG_TYPE_RWIMG: | |
457 | { | |
458 | /* Handle images and samplers as target-specific blobs of data | |
459 | that should be allocated earlier on from the runtime side. | |
460 | Create a void* that should be initialized to point to the blobs | |
461 | by the kernel launcher. Images and samplers are accessed | |
462 | via builtins that take void* as the reference. TODO: who and | |
463 | how these arrays should be initialized? */ | |
464 | tree void_ptr = build_pointer_type (void_type_node); | |
465 | return void_ptr; | |
466 | } | |
467 | default: | |
468 | gcc_unreachable (); | |
469 | break; | |
470 | } | |
471 | } | |
472 | ||
473 | /* Drop const qualifiers. */ | |
474 | return tree_type; | |
475 | } |