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