Mercurial > hg > CbC > CbC_gcc
diff gcc/brig/brigfrontend/brig-util.cc @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/brig/brigfrontend/brig-util.cc Fri Oct 27 22:46:09 2017 +0900 @@ -0,0 +1,475 @@ +/* brig-util.cc -- gccbrig utility functions + Copyright (C) 2016-2017 Free Software Foundation, Inc. + Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com> + for General Processor Tech. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include <sstream> + +#include "stdint.h" +#include "hsa-brig-format.h" +#include "brig-util.h" +#include "errors.h" +#include "diagnostic-core.h" + +bool +group_variable_offset_index::has_variable (const std::string &name) const +{ + varname_offset_table::const_iterator i = m_group_offsets.find (name); + return i != m_group_offsets.end (); +} + +/* Adds a new group segment variable. */ + +void +group_variable_offset_index::add (const std::string &name, size_t size, + size_t alignment) +{ + size_t align_padding = m_next_group_offset % alignment == 0 ? + 0 : (alignment - m_next_group_offset % alignment); + m_next_group_offset += align_padding; + m_group_offsets[name] = m_next_group_offset; + m_next_group_offset += size; +} + +size_t +group_variable_offset_index::segment_offset (const std::string &name) const +{ + varname_offset_table::const_iterator i = m_group_offsets.find (name); + gcc_assert (i != m_group_offsets.end ()); + return (*i).second; +} + +/* Return true if operand number OPNUM of instruction with OPCODE is an output. + False if it is an input. Some code reused from Martin Jambor's gcc-hsa + tree. */ + +bool +gccbrig_hsa_opcode_op_output_p (BrigOpcode16_t opcode, int opnum) +{ + switch (opcode) + { + case BRIG_OPCODE_BR: + case BRIG_OPCODE_SBR: + case BRIG_OPCODE_CBR: + case BRIG_OPCODE_ST: + case BRIG_OPCODE_ATOMICNORET: + case BRIG_OPCODE_SIGNALNORET: + case BRIG_OPCODE_INITFBAR: + case BRIG_OPCODE_JOINFBAR: + case BRIG_OPCODE_WAITFBAR: + case BRIG_OPCODE_ARRIVEFBAR: + case BRIG_OPCODE_LEAVEFBAR: + case BRIG_OPCODE_RELEASEFBAR: + case BRIG_OPCODE_DEBUGTRAP: + return false; + default: + return opnum == 0; + } +} + +unsigned +gccbrig_hsa_type_bit_size (BrigType16_t t) +{ + + unsigned pack_type = t & ~BRIG_TYPE_BASE_MASK; + + if (pack_type == BRIG_TYPE_PACK_32) + return 32; + else if (pack_type == BRIG_TYPE_PACK_64) + return 64; + else if (pack_type == BRIG_TYPE_PACK_128) + return 128; + + switch (t) + { + case BRIG_TYPE_NONE: + return 0; + + case BRIG_TYPE_B1: + return 1; + + case BRIG_TYPE_U8: + case BRIG_TYPE_S8: + case BRIG_TYPE_B8: + return 8; + + case BRIG_TYPE_U16: + case BRIG_TYPE_S16: + case BRIG_TYPE_B16: + case BRIG_TYPE_F16: + return 16; + + case BRIG_TYPE_U32: + case BRIG_TYPE_S32: + case BRIG_TYPE_B32: + case BRIG_TYPE_F32: + case BRIG_TYPE_U8X4: + case BRIG_TYPE_U16X2: + case BRIG_TYPE_S8X4: + case BRIG_TYPE_S16X2: + case BRIG_TYPE_F16X2: + case BRIG_TYPE_SIG32: + return 32; + + case BRIG_TYPE_U64: + case BRIG_TYPE_S64: + case BRIG_TYPE_F64: + case BRIG_TYPE_B64: + case BRIG_TYPE_U8X8: + case BRIG_TYPE_U16X4: + case BRIG_TYPE_U32X2: + case BRIG_TYPE_S8X8: + case BRIG_TYPE_S16X4: + case BRIG_TYPE_S32X2: + case BRIG_TYPE_F16X4: + case BRIG_TYPE_F32X2: + case BRIG_TYPE_SIG64: + return 64; + + case BRIG_TYPE_B128: + case BRIG_TYPE_U8X16: + case BRIG_TYPE_U16X8: + case BRIG_TYPE_U32X4: + case BRIG_TYPE_U64X2: + case BRIG_TYPE_S8X16: + case BRIG_TYPE_S16X8: + case BRIG_TYPE_S32X4: + case BRIG_TYPE_S64X2: + case BRIG_TYPE_F16X8: + case BRIG_TYPE_F32X4: + case BRIG_TYPE_F64X2: + return 128; + + default: + printf ("HMM %d %x\n", t, t); + gcc_unreachable (); + } +} + +/* gcc-hsa borrowed code ENDS. */ + +uint64_t +gccbrig_to_uint64_t (const BrigUInt64 &brig_type) +{ + return (uint64_t (brig_type.hi) << 32) | uint64_t (brig_type.lo); +} + +int +gccbrig_reg_size (const BrigOperandRegister *brig_reg) +{ + switch (brig_reg->regKind) + { + case BRIG_REGISTER_KIND_CONTROL: + return 1; + case BRIG_REGISTER_KIND_SINGLE: + return 32; + case BRIG_REGISTER_KIND_DOUBLE: + return 64; + case BRIG_REGISTER_KIND_QUAD: + return 128; + default: + gcc_unreachable (); + break; + } +} + +std::string +gccbrig_reg_name (const BrigOperandRegister *reg) +{ + std::ostringstream strstr; + switch (reg->regKind) + { + case BRIG_REGISTER_KIND_CONTROL: + strstr << 'c'; + break; + case BRIG_REGISTER_KIND_SINGLE: + strstr << 's'; + break; + case BRIG_REGISTER_KIND_DOUBLE: + strstr << 'd'; + break; + case BRIG_REGISTER_KIND_QUAD: + strstr << 'q'; + break; + default: + gcc_unreachable (); + return ""; + } + strstr << reg->regNum; + return strstr.str (); +} + +std::string +gccbrig_type_name (BrigType16_t type) +{ + switch (type) + { + case BRIG_TYPE_U8: + return "u8"; + case BRIG_TYPE_U16: + return "u16"; + case BRIG_TYPE_U32: + return "u32"; + case BRIG_TYPE_U64: + return "u64"; + case BRIG_TYPE_S8: + return "s8"; + case BRIG_TYPE_S16: + return "s16"; + case BRIG_TYPE_S32: + return "s32"; + case BRIG_TYPE_S64: + return "s64"; + default: + gcc_unreachable (); + break; + } +} + +std::string +gccbrig_segment_name (BrigSegment8_t segment) +{ + if (segment == BRIG_SEGMENT_GLOBAL) + return "global"; + else if (segment == BRIG_SEGMENT_GROUP) + return "group"; + else if (segment == BRIG_SEGMENT_PRIVATE) + return "private"; + else + gcc_unreachable (); +} + +bool +gccbrig_is_float_type (BrigType16_t type) +{ + return (type == BRIG_TYPE_F32 || type == BRIG_TYPE_F64 + || type == BRIG_TYPE_F16); +} + +BrigType16_t +gccbrig_tree_type_to_hsa_type (tree tree_type) +{ + if (INTEGRAL_TYPE_P (tree_type)) + { + if (TYPE_UNSIGNED (tree_type)) + { + switch (int_size_in_bytes (tree_type)) + { + case 1: + return BRIG_TYPE_U8; + case 2: + return BRIG_TYPE_U16; + case 4: + return BRIG_TYPE_U32; + case 8: + return BRIG_TYPE_U64; + default: + break; + } + } + else + { + switch (int_size_in_bytes (tree_type)) + { + case 1: + return BRIG_TYPE_S8; + case 2: + return BRIG_TYPE_S16; + case 4: + return BRIG_TYPE_S32; + case 8: + return BRIG_TYPE_S64; + default: + break; + } + } + } + else if (VECTOR_TYPE_P (tree_type)) + { + tree element_type = TREE_TYPE (tree_type); + size_t element_size = int_size_in_bytes (element_type) * 8; + BrigType16_t brig_element_type; + switch (element_size) + { + case 8: + brig_element_type + = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U8 : BRIG_TYPE_S8; + break; + case 16: + brig_element_type + = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U16 : BRIG_TYPE_S16; + break; + case 32: + brig_element_type + = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U32 : BRIG_TYPE_S32; + break; + case 64: + brig_element_type + = TYPE_UNSIGNED (element_type) ? BRIG_TYPE_U64 : BRIG_TYPE_S64; + break; + default: + gcc_unreachable (); + } + + BrigType16_t pack_type; + switch (int_size_in_bytes (tree_type) * 8) + { + case 32: + pack_type = BRIG_TYPE_PACK_32; + break; + case 64: + pack_type = BRIG_TYPE_PACK_64; + break; + case 128: + pack_type = BRIG_TYPE_PACK_128; + break; + default: + gcc_unreachable (); + } + return brig_element_type | pack_type; + } + gcc_unreachable (); +} + +/* Returns true in case the operation is a "bit level" operation, + that is, not having operand type depending semantical differences. */ + +bool +gccbrig_is_bit_operation (BrigOpcode16_t opcode) +{ + return opcode == BRIG_OPCODE_CMOV || opcode == BRIG_OPCODE_SHUFFLE + || opcode == BRIG_OPCODE_UNPACK || opcode == BRIG_OPCODE_UNPACKLO + || opcode == BRIG_OPCODE_UNPACKHI || opcode == BRIG_OPCODE_ST + || opcode == BRIG_OPCODE_PACK; +} + +/* The program scope definition can be left external within the + kernel binary which means it must be defined by the host via + HSA runtime. For these we have special treatment: + Create additional pointer indirection when accessing the variable + value from kernel code through a generated pointer + __gccbrig_ptr_variable_name. The pointer value then can be set either + within the kernel binary (in case of a later linked in definition) + or from the host. */ + +bool +gccbrig_might_be_host_defined_var_p (const BrigDirectiveVariable *brigVar) +{ + bool is_definition = brigVar->modifier & BRIG_VARIABLE_DEFINITION; + return (brigVar->segment == BRIG_SEGMENT_GLOBAL + || brigVar->segment == BRIG_SEGMENT_READONLY) && !is_definition + && brigVar->linkage == BRIG_LINKAGE_PROGRAM + && (brigVar->allocation == BRIG_ALLOCATION_PROGRAM + || brigVar->allocation == BRIG_ALLOCATION_AGENT); +} + +/* Produce a GENERIC type for the given HSA/BRIG type. Returns the element + type in case of vector instructions. */ + +tree +gccbrig_tree_type_for_hsa_type (BrigType16_t brig_type) +{ + tree tree_type = NULL_TREE; + + if (hsa_type_packed_p (brig_type)) + { + /* The element type is encoded in the bottom 5 bits. */ + BrigType16_t inner_brig_type = brig_type & BRIG_TYPE_BASE_MASK; + + unsigned full_size = gccbrig_hsa_type_bit_size (brig_type); + + if (inner_brig_type == BRIG_TYPE_F16) + return build_vector_type (gccbrig_tree_type_for_hsa_type (BRIG_TYPE_U16), + full_size / 16); + + tree inner_type = gccbrig_tree_type_for_hsa_type (inner_brig_type); + + unsigned inner_size = gccbrig_hsa_type_bit_size (inner_brig_type); + unsigned nunits = full_size / inner_size; + tree_type = build_vector_type (inner_type, nunits); + } + else + { + switch (brig_type) + { + case BRIG_TYPE_NONE: + tree_type = void_type_node; + break; + case BRIG_TYPE_B1: + tree_type = boolean_type_node; + break; + case BRIG_TYPE_S8: + case BRIG_TYPE_S16: + case BRIG_TYPE_S32: + case BRIG_TYPE_S64: + /* Ensure a fixed width integer. */ + tree_type + = build_nonstandard_integer_type + (gccbrig_hsa_type_bit_size (brig_type), false); + break; + case BRIG_TYPE_U8: + return unsigned_char_type_node; + case BRIG_TYPE_U16: + case BRIG_TYPE_U32: + case BRIG_TYPE_U64: + case BRIG_TYPE_B8: /* Handle bit vectors as unsigned ints. */ + case BRIG_TYPE_B16: + case BRIG_TYPE_B32: + case BRIG_TYPE_B64: + case BRIG_TYPE_B128: + case BRIG_TYPE_SIG32: /* Handle signals as integers for now. */ + case BRIG_TYPE_SIG64: + tree_type = build_nonstandard_integer_type + (gccbrig_hsa_type_bit_size (brig_type), true); + break; + case BRIG_TYPE_F16: + tree_type = uint16_type_node; + break; + case BRIG_TYPE_F32: + /* TODO: make sure that the alignment of the float are at least as + strict than mandated by HSA, and conform to IEEE (like mandated + by HSA). */ + tree_type = float_type_node; + break; + case BRIG_TYPE_F64: + tree_type = double_type_node; + break; + case BRIG_TYPE_SAMP: + case BRIG_TYPE_ROIMG: + case BRIG_TYPE_WOIMG: + case BRIG_TYPE_RWIMG: + { + /* Handle images and samplers as target-specific blobs of data + that should be allocated earlier on from the runtime side. + Create a void* that should be initialized to point to the blobs + by the kernel launcher. Images and samplers are accessed + via builtins that take void* as the reference. TODO: who and + how these arrays should be initialized? */ + tree void_ptr = build_pointer_type (void_type_node); + return void_ptr; + } + default: + gcc_unreachable (); + break; + } + } + + /* Drop const qualifiers. */ + return tree_type; +}