diff gcc/brig/brigfrontend/brig-to-generic.cc @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
line wrap: on
line diff
--- a/gcc/brig/brigfrontend/brig-to-generic.cc	Fri Oct 27 22:46:09 2017 +0900
+++ b/gcc/brig/brigfrontend/brig-to-generic.cc	Thu Oct 25 07:37:49 2018 +0900
@@ -1,5 +1,5 @@
 /* brig2tree.cc -- brig to gcc generic/gimple tree conversion
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+   Copyright (C) 2016-2018 Free Software Foundation, Inc.
    Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
    for General Processor Tech.
 
@@ -52,6 +52,7 @@
 #include "cgraph.h"
 #include "dumpfile.h"
 #include "tree-pretty-print.h"
+#include "attribs.h"
 
 extern int gccbrig_verbose;
 
@@ -124,6 +125,24 @@
   }
 };
 
+class brig_reg_use_analyzer : public brig_code_entry_handler
+{
+public:
+  brig_reg_use_analyzer (brig_to_generic &parent)
+    : brig_code_entry_handler (parent)
+  {
+  }
+
+  size_t
+  operator () (const BrigBase *base)
+  {
+    const BrigInstBase *brig_inst = (const BrigInstBase *) base;
+    analyze_operands (*brig_inst);
+    return base->byteCount;
+  }
+
+};
+
 /* Helper struct for pairing a BrigKind and a BrigCodeEntryHandler that
    should handle its data.  */
 
@@ -210,6 +229,7 @@
   brig_directive_variable_handler var_handler (*this);
   brig_directive_fbarrier_handler fbar_handler (*this);
   brig_directive_function_handler func_handler (*this);
+  brig_reg_use_analyzer reg_use_analyzer (*this);
 
   /* Need this for grabbing the module names for mangling the
      group variable names.  */
@@ -219,7 +239,21 @@
   const BrigSectionHeader *csection_header = (const BrigSectionHeader *) m_code;
 
   code_entry_handler_info handlers[]
-    = {{BRIG_KIND_DIRECTIVE_VARIABLE, &var_handler},
+    = {{BRIG_KIND_INST_BASIC, &reg_use_analyzer},
+       {BRIG_KIND_INST_MOD, &reg_use_analyzer},
+       {BRIG_KIND_INST_CMP, &reg_use_analyzer},
+       {BRIG_KIND_INST_MEM, &reg_use_analyzer},
+       {BRIG_KIND_INST_CVT, &reg_use_analyzer},
+       {BRIG_KIND_INST_SEG_CVT, &reg_use_analyzer},
+       {BRIG_KIND_INST_SEG, &reg_use_analyzer},
+       {BRIG_KIND_INST_ADDR, &reg_use_analyzer},
+       {BRIG_KIND_INST_SOURCE_TYPE, &reg_use_analyzer},
+       {BRIG_KIND_INST_ATOMIC, &reg_use_analyzer},
+       {BRIG_KIND_INST_SIGNAL, &reg_use_analyzer},
+       {BRIG_KIND_INST_BR, &reg_use_analyzer},
+       {BRIG_KIND_INST_LANE, &reg_use_analyzer},
+       {BRIG_KIND_INST_QUEUE, &reg_use_analyzer},
+       {BRIG_KIND_DIRECTIVE_VARIABLE, &var_handler},
        {BRIG_KIND_DIRECTIVE_FBARRIER, &fbar_handler},
        {BRIG_KIND_DIRECTIVE_KERNEL, &func_handler},
        {BRIG_KIND_DIRECTIVE_MODULE, &module_handler},
@@ -454,7 +488,9 @@
   tree var_addr = build1 (ADDR_EXPR, ptype, var_decl);
 
   DECL_INITIAL (host_def_var) = var_addr;
-  TREE_PUBLIC (host_def_var) = 0;
+  TREE_PUBLIC (host_def_var) = 1;
+
+  set_externally_visible (host_def_var);
 }
 
 /* Adds an indirection pointer for a potential host-defined program scope
@@ -477,10 +513,18 @@
   TREE_ADDRESSABLE (ptr_var) = 1;
   TREE_STATIC (ptr_var) = 1;
 
+  set_externally_visible (ptr_var);
+
   append_global (ptr_var);
   m_global_variables[var_name] = ptr_var;
 }
 
+void
+brig_to_generic::add_decl_call (tree call)
+{
+  m_decl_call.push_back (call);
+}
+
 /* Produce a "mangled name" for the given brig function or kernel.
    The mangling is used to make unique global symbol name in case of
    module scope functions.  Program scope functions are not mangled
@@ -555,10 +599,14 @@
    than the created reg var type in order to select correct instruction type
    later on.  This function creates the necessary reinterpret type cast from
    a source variable to the destination type.  In case no cast is needed to
-   the same type, SOURCE is returned directly.  */
+   the same type, SOURCE is returned directly.
+
+   In case of mismatched type sizes, casting:
+   - to narrower type the upper bits are clipped and
+   - to wider type the source value is zero extended.  */
 
 tree
-build_reinterpret_cast (tree destination_type, tree source)
+build_resize_convert_view (tree destination_type, tree source)
 {
 
   gcc_assert (source && destination_type && TREE_TYPE (source) != NULL_TREE
@@ -578,23 +626,30 @@
   size_t dst_size = int_size_in_bytes (destination_type);
   if (src_size == dst_size)
     return build1 (VIEW_CONVERT_EXPR, destination_type, source);
-  else if (src_size < dst_size)
+  else /* src_size != dst_size  */
     {
       /* The src_size can be smaller at least with f16 scalars which are
 	 stored to 32b register variables.  First convert to an equivalent
 	 size unsigned type, then extend to an unsigned type of the
 	 target width, after which VIEW_CONVERT_EXPR can be used to
 	 force to the target type.  */
-      tree unsigned_temp = build1 (VIEW_CONVERT_EXPR,
-				   get_unsigned_int_type (source_type),
-				   source);
-      return build1 (VIEW_CONVERT_EXPR, destination_type,
-		     convert (get_unsigned_int_type (destination_type),
-			      unsigned_temp));
+      tree resized = convert (get_scalar_unsigned_int_type (destination_type),
+			      build_reinterpret_to_uint (source));
+      gcc_assert ((size_t)int_size_in_bytes (TREE_TYPE (resized)) == dst_size);
+      return build_resize_convert_view (destination_type, resized);
     }
-  else
-    gcc_unreachable ();
-  return NULL_TREE;
+}
+
+/* Reinterprets SOURCE as a scalar unsigned int with the size
+   corresponding to the orignal.  */
+
+tree build_reinterpret_to_uint (tree source)
+{
+  tree src_type = TREE_TYPE (source);
+  if (INTEGRAL_TYPE_P (src_type) && TYPE_UNSIGNED (src_type))
+    return source;
+  tree dest_type = get_scalar_unsigned_int_type (src_type);
+  return build1 (VIEW_CONVERT_EXPR, dest_type, source);
 }
 
 /* Returns the finished brig_function for the given generic FUNC_DECL,
@@ -657,8 +712,6 @@
       m_cf->finish ();
       m_cf->emit_metadata (stmts);
       dump_function (m_dump_file, m_cf);
-      gimplify_function_tree (m_cf->m_func_decl);
-      cgraph_node::finalize_function (m_cf->m_func_decl, true);
     }
   else
     /* Emit the kernel only at the very end so we can analyze the total
@@ -775,7 +828,7 @@
     {
       types[i] = va_arg (ap, tree);
       tree arg = va_arg (ap, tree);
-      args[i] = build_reinterpret_cast (types[i], arg);
+      args[i] = build_resize_convert_view (types[i], arg);
       if (types[i] == error_mark_node || args[i] == error_mark_node)
 	{
 	  delete[] types;
@@ -802,6 +855,43 @@
 void
 brig_to_generic::write_globals ()
 {
+
+  /* Replace calls to declarations with calls to definitions.  Otherwise
+     inlining will fail to find the definition to inline from.  */
+
+  for (size_t i = 0; i < m_decl_call.size(); ++i)
+    {
+      tree decl_call = m_decl_call.at(i);
+      tree func_decl = get_callee_fndecl (decl_call);
+      brig_function *brig_function = get_finished_function (func_decl);
+
+      if (brig_function && brig_function->m_func_decl
+	  && DECL_EXTERNAL (brig_function->m_func_decl) == 0
+	  && brig_function->m_func_decl != func_decl)
+	{
+
+	  decl_call = CALL_EXPR_FN (decl_call);
+	  STRIP_NOPS (decl_call);
+	  if (TREE_CODE (decl_call) == ADDR_EXPR
+	      && TREE_CODE (TREE_OPERAND (decl_call, 0)) == FUNCTION_DECL)
+	    TREE_OPERAND (decl_call, 0) = brig_function->m_func_decl;
+	}
+    }
+
+  for (std::map<std::string, brig_function *>::iterator i
+	 = m_finished_functions.begin(), e = m_finished_functions.end();
+       i != e; ++i)
+    {
+      brig_function *brig_f = (*i).second;
+      if (brig_f->m_is_kernel)
+	continue;
+
+      /* Finalize only at this point to allow the cgraph analysis to
+	 see definitions to calls to later functions.  */
+      gimplify_function_tree (brig_f->m_func_decl);
+      cgraph_node::finalize_function (brig_f->m_func_decl, true);
+    }
+
   /* Now that the whole BRIG module has been processed, build a launcher
      and a metadata section for each built kernel.  */
   for (size_t i = 0; i < m_kernels.size (); ++i)
@@ -836,6 +926,18 @@
 
       append_global (launcher);
 
+      if (m_dump_file)
+	{
+	  std::string kern_name = f->m_name.substr (1);
+	  fprintf (m_dump_file, "\n;; Function %s", kern_name.c_str());
+	  fprintf (m_dump_file, "\n;; enabled by -%s\n\n",
+		   dump_flag_name (TDI_original));
+	  print_generic_decl (m_dump_file, launcher, TDF_NONE);
+	  print_generic_expr (m_dump_file, DECL_SAVED_TREE (launcher),
+			      TDF_NONE);
+	  fprintf (m_dump_file, "\n");
+	}
+
       gimplify_function_tree (launcher);
       cgraph_node::finalize_function (launcher, true);
       pop_cfun ();
@@ -869,7 +971,7 @@
     {
       size_t esize
 	= int_size_in_bytes (TREE_TYPE (original_type)) * BITS_PER_UNIT;
-      size_t ecount = TYPE_VECTOR_SUBPARTS (original_type);
+      poly_uint64 ecount = TYPE_VECTOR_SUBPARTS (original_type);
       return build_vector_type (build_nonstandard_integer_type (esize, true),
 				ecount);
     }
@@ -879,6 +981,35 @@
 					   true);
 }
 
+/* Returns a type with unsigned int corresponding to the size
+   ORIGINAL_TYPE.  */
+
+tree
+get_scalar_unsigned_int_type (tree original_type)
+{
+  return build_nonstandard_integer_type (int_size_in_bytes (original_type)
+					 * BITS_PER_UNIT, true);
+}
+
+/* Set the declaration externally visible so it won't get removed by
+   whole program optimizations.  */
+
+void
+set_externally_visible (tree decl)
+{
+  if (!lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
+    DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("externally_visible"),
+					NULL, DECL_ATTRIBUTES (decl));
+}
+
+void
+set_inline (tree decl)
+{
+  if (!lookup_attribute ("inline", DECL_ATTRIBUTES (decl)))
+    DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("inline"),
+					NULL, DECL_ATTRIBUTES (decl));
+}
+
 void
 dump_function (FILE *dump_file, brig_function *f)
 {
@@ -888,8 +1019,27 @@
       fprintf (dump_file, "\n;; Function %s", f->m_name.c_str ());
       fprintf (dump_file, "\n;; enabled by -%s\n\n",
 	       dump_flag_name (TDI_original));
-      print_generic_decl (dump_file, f->m_func_decl, 0);
-      print_generic_expr (dump_file, f->m_current_bind_expr, 0);
+      print_generic_decl (dump_file, f->m_func_decl, TDF_NONE);
+      print_generic_expr (dump_file, f->m_current_bind_expr, TDF_NONE);
       fprintf (dump_file, "\n");
     }
 }
+
+/* Records use of the BRIG_REG as a TYPE in the current function.  */
+
+void
+brig_to_generic::add_reg_used_as_type (const BrigOperandRegister &brig_reg,
+				       tree type)
+{
+  gcc_assert (m_cf);
+  reg_use_info &info
+    = m_fn_regs_use_index[m_cf->m_name][gccbrig_hsa_reg_id (brig_reg)];
+
+  if (info.m_type_refs_lookup.count (type))
+    info.m_type_refs[info.m_type_refs_lookup[type]].second++;
+  else
+    {
+      info.m_type_refs.push_back (std::make_pair (type, 1));
+      info.m_type_refs_lookup[type] = info.m_type_refs.size () - 1;
+    }
+}