]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/brig/brigfrontend/brig-util.cc
Brig front-end
[thirdparty/gcc.git] / gcc / brig / brigfrontend / brig-util.cc
CommitLineData
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
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"
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
34bool
35gccbrig_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
58unsigned
59gccbrig_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
139uint64_t
140gccbrig_to_uint64_t (const BrigUInt64 &brig_type)
141{
142 return (uint64_t (brig_type.hi) << 32) | uint64_t (brig_type.lo);
143}
144
145int
146gccbrig_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
164std::string
165gccbrig_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
190std::string
191gccbrig_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
217std::string
218gccbrig_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
230bool
231gccbrig_is_float_type (BrigType16_t type)
232{
233 return (type == BRIG_TYPE_F32 || type == BRIG_TYPE_F64
234 || type == BRIG_TYPE_F16);
235}
236
237BrigType16_t
238gccbrig_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
325bool
326gccbrig_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
343bool
344gccbrig_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
357tree
358gccbrig_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}