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;
+}