This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[HSA] Introduce support for shared libraries and host fallback


Hello.

Following patch set introduces HSA support for BRIG shared libraries. Apart from that,
it adds new warning option (-Whsa) that pops up when HSA code generation cannot expand
a function. Moreover, remaining of patches are follow-up of previous big changes.

Thanks,
Martin
>From 89d0a81c84cbbc18af05a6c144ec5f84fbd55a36 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Fri, 2 Oct 2015 10:44:00 +0200
Subject: [PATCH 1/9] HSA: introduce warnings and libgomp host fallback
 support.

gcc/ChangeLog:

2015-10-02  Martin Liska  <mliska@suse.cz>

	* common.opt: Add new Whsa option.
	* hsa-gen.c (hsa_function_representation::hsa_function_representation):
	Add new member seen_error.
	(hsa_type_for_scalar_tree_type): Use HSA_SORRY_AT{V} instread of
	sorry.
	(hsa_type_for_tree_type): Likewise.
	(hsa_op_immed::hsa_op_immed): Likewise.
	(process_mem_base): Likewise.
	(gen_hsa_addr): Likewise.
	(gen_hsa_insns_for_load): Likewise.
	(gen_hsa_insns_for_store): Likewise.
	(gen_hsa_ctor_assignment): Likewise.
	(gen_hsa_insns_for_single_assignment): Likewise.
	(gen_hsa_cmp_insn_from_gimple): Likewise.
	(gen_hsa_insns_for_operation_assignment): Likewise.
	(verify_function_arguments): Likewise.
	(gen_hsa_insns_for_direct_call): Likewise.
	(gen_hsa_insns_for_return): Likewise.
	(get_address_from_value): Likewise.
	(gen_hsa_insns_for_call): Likewise.
	(gen_hsa_insns_for_gimple_stmt): Likewise.
	(gen_hsa_phi_from_gimple_phi): Likewise.
	(gen_body_from_gimple): Use aforementioned hsa_cfun->seen_error.
	(generate_hsa): Likewise.
	* hsa.c (hsa_deinit_compilation_unit_data): Release
	hsa_failed_functions.
	(hsa_seen_error): New function.
	* hsa.h (hsa_failed_functions): New variable.

libgomp/ChangeLog:

2015-10-02  Martin Liska  <mliska@suse.cz>

	* libgomp.h (struct gomp_device_descr): Add new function
	pointer (can_run_func).
	* plugin/plugin-hsa.c (init_enviroment_variables): Rename this
	function from init_debug.
	(hsa_warn): New function.
	(struct kernel_info): Add new member variable
	initialization_failed.
	(struct agent_info): Add new member variable
	prog_finalized_error.
	(get_kernel_in_module): Do not call GOMP_PLUGIN_fatal.
	(init_hsa_context): Use HSA_DEBUG macro.
	(GOMP_OFFLOAD_init_device): Likewise.
	(destroy_hsa_program): Likewise.
	(GOMP_OFFLOAD_load_image): Produce warnings instread
	of failures.
	(GOMP_OFFLOAD_unload_image): Do not check if the agent
	is initialized, the check is in the called function.
	(GOMP_OFFLOAD_fini_device): Likewise.
	(create_and_finalize_hsa_program): Likewise.
	(release_kernel_dispatch): Use HSA_DEBUG macro.
	(init_single_kernel): Produce warnings instread of failures.
	(init_kernel): Use HSA_DEBUG macro.
	(parse_launch_attributes): Likewise.
	(GOMP_OFFLOAD_can_run): New function.
	(GOMP_OFFLOAD_run): Remove part of initialization that
	is moved to GOMP_OFFLOAD_can_run.
	(GOMP_OFFLOAD_fini_device): Fix coding style.
	* target.c (run_on_host): New function.
	(GOMP_target): Use the function.
	(gomp_load_plugin_for_device): Dynamically load the new hook.
---
 gcc/common.opt              |   4 +
 gcc/hsa-gen.c               | 238 ++++++++++++++++++++++++++++----------------
 gcc/hsa.c                   |  14 ++-
 gcc/hsa.h                   |   4 +
 libgomp/libgomp.h           |   1 +
 libgomp/plugin/plugin-hsa.c | 230 ++++++++++++++++++++++++++++--------------
 libgomp/target.c            |  42 +++++---
 7 files changed, 359 insertions(+), 174 deletions(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 7b0ec96..5ef6f46 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -581,6 +581,10 @@ Wfree-nonheap-object
 Common Var(warn_free_nonheap_object) Init(1) Warning
 Warn when attempting to free a non-heap object
 
+Whsa
+Common Var(warn_hsa) Init(1) Warning
+Warn when a function cannot be expanded to HSAIL
+
 Winline
 Common Var(warn_inline) Warning
 Warn when an inlined function cannot be inlined
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 291d650..fb17a25 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -77,6 +77,32 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "cfganal.h"
 
+/* Print a warning message and set that we have seen an error.  */
+
+#define HSA_SORRY_MSG "could not emit HSAIL for the function"
+
+#define HSA_SORRY_ATV(location, message, ...) \
+  do \
+  { \
+    hsa_cfun->seen_error = true; \
+    if (warning_at (EXPR_LOCATION (hsa_cfun->decl), OPT_Whsa, \
+		    HSA_SORRY_MSG)) \
+      inform (location, message, ##__VA_ARGS__); \
+  } \
+  while (false);
+
+/* Same as previous, but highlight a location.  */
+
+#define HSA_SORRY_AT(location, message) \
+  do \
+  { \
+    hsa_cfun->seen_error = true; \
+    if (warning_at (EXPR_LOCATION (hsa_cfun->decl), OPT_Whsa, \
+		    HSA_SORRY_MSG)) \
+      inform (location, message); \
+  } \
+  while (false);
+
 /* Following structures are defined in the final version
    of HSA specification.  */
 
@@ -196,6 +222,7 @@ hsa_function_representation::hsa_function_representation ()
   shadow_reg = NULL;
   kernel_dispatch_count = 0;
   maximum_omp_data_size = 0;
+  seen_error = false;
 }
 
 /* Destructor of class holding function/kernel-wide informaton and state.  */
@@ -439,8 +466,9 @@ hsa_type_for_scalar_tree_type (const_tree type, bool min32int)
 
   if (!tree_fits_uhwi_p (TYPE_SIZE (base)))
     {
-      sorry ("Support for HSA does not implement huge or variable-sized type %T",
-	     type);
+      HSA_SORRY_ATV (EXPR_LOCATION (type),
+		     "support for HSA does not implement huge or "
+		     "variable-sized type %T", type);
       return res;
     }
 
@@ -468,7 +496,8 @@ hsa_type_for_scalar_tree_type (const_tree type, bool min32int)
 
   if (res == BRIG_TYPE_NONE)
     {
-      sorry ("Support for HSA does not implement type %T", type);
+      HSA_SORRY_ATV (EXPR_LOCATION (type),
+		     "support for HSA does not implement type %T", type);
       return res;
     }
 
@@ -478,8 +507,9 @@ hsa_type_for_scalar_tree_type (const_tree type, bool min32int)
 
       if (bsize == tsize)
 	{
-	  sorry ("Support for HSA does not implement a vector type where "
-		 "a type and unit size are equal: %T", type);
+	  HSA_SORRY_ATV (EXPR_LOCATION (type),
+			 "support for HSA does not implement a vector type "
+			 "where a type and unit size are equal: %T", type);
 	  return res;
 	}
 
@@ -495,7 +525,8 @@ hsa_type_for_scalar_tree_type (const_tree type, bool min32int)
 	  res |= BRIG_TYPE_PACK_128;
 	  break;
 	default:
-	  sorry ("Support for HSA does not implement type %T", type);
+	  HSA_SORRY_ATV (EXPR_LOCATION (type),
+			 "support for HSA does not implement type %T", type);
 	}
     }
 
@@ -538,8 +569,8 @@ hsa_type_for_tree_type (const_tree type, unsigned HOST_WIDE_INT *dim_p = NULL,
   gcc_checking_assert (TYPE_P (type));
   if (!tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
     {
-      sorry ("Support for HSA does not implement huge or variable-sized type %T",
-	     type);
+      HSA_SORRY_ATV (EXPR_LOCATION (type), "support for HSA does not "
+		     "implement huge or variable-sized type %T", type);
       return BRIG_TYPE_NONE;
     }
 
@@ -566,8 +597,9 @@ hsa_type_for_tree_type (const_tree type, unsigned HOST_WIDE_INT *dim_p = NULL,
 	      || !tree_fits_shwi_p (TYPE_MIN_VALUE (domain))
 	      || !tree_fits_shwi_p (TYPE_MAX_VALUE (domain)))
 	    {
-	      sorry ("Support for HSA does not implement array %T with unknown "
-		     "bounds", type);
+	      HSA_SORRY_ATV (EXPR_LOCATION (type),
+			     "support for HSA does not implement array %T with "
+			     "unknown bounds", type);
 	      return BRIG_TYPE_NONE;
 	    }
 	  HOST_WIDE_INT min = tree_to_shwi (TYPE_MIN_VALUE (domain));
@@ -775,7 +807,7 @@ hsa_op_immed::hsa_op_immed (tree tree_val, bool min32int)
 		      hsa_type_for_tree_type (TREE_TYPE (tree_val), NULL,
 					      min32int))
 {
-  if (seen_error ())
+  if (hsa_seen_error ())
     return;
 
   gcc_checking_assert ((is_gimple_min_invariant (tree_val)
@@ -798,7 +830,8 @@ hsa_op_immed::hsa_op_immed (tree tree_val, bool min32int)
 	  tree v = CONSTRUCTOR_ELT (tree_value, i)->value;
 	  if (!CONSTANT_CLASS_P (v))
 	    {
-	      sorry ("HSA ctor should have only constants");
+	      HSA_SORRY_AT (EXPR_LOCATION (tree_val),
+			    "HSA ctor should have only constants");
 	      return;
 	    }
 	}
@@ -1636,8 +1669,9 @@ process_mem_base (tree base, hsa_symbol **symbol, BrigType16_t *addrtype,
 
       if (!DECL_P (decl) || TREE_CODE (decl) == FUNCTION_DECL)
 	{
-	  sorry ("Support for HSA does not implement a memory reference to "
-		 "a non-declaration type");
+	  HSA_SORRY_AT (EXPR_LOCATION (base),
+			"support for HSA does not implement a memory reference "
+			"to a non-declaration type");
 	  return;
 	}
 
@@ -1682,8 +1716,9 @@ gen_hsa_addr (tree ref, hsa_bb *hbb, vec <hsa_op_reg_p> *ssa_map,
 	   && ((tree_to_uhwi (TREE_OPERAND (ref, 1)) % BITS_PER_UNIT) != 0
 	       || (tree_to_uhwi (TREE_OPERAND (ref, 2)) % BITS_PER_UNIT) != 0))
     {
-      sorry ("Support for HSA does not implement bit field references "
-	     "such as %E", ref);
+      HSA_SORRY_ATV (EXPR_LOCATION (origref),
+		     "support for HSA does not implement "
+		     "bit field references such as %E", ref);
       goto out;
     }
 
@@ -1758,11 +1793,13 @@ gen_hsa_addr (tree ref, hsa_bb *hbb, vec <hsa_op_reg_p> *ssa_map,
       offset += wi::to_offset (TMR_OFFSET (ref));
       break;
     case FUNCTION_DECL:
-      sorry ("HSA does not support indirect calls");
+      HSA_SORRY_AT (EXPR_LOCATION (origref),
+		    "support for HSA does not implement function pointers");
       goto out;
     case SSA_NAME:
     default:
-      sorry ("Support for HSA does not implement memory access to %E", origref);
+      HSA_SORRY_ATV (EXPR_LOCATION (origref), "support for HSA does "
+		     "not implement memory access to %E", origref);
       goto out;
     }
 
@@ -1797,8 +1834,8 @@ out:
     bitsize = 0;
 
   if ((bitpos || bitsize) && (output_bitpos == NULL || output_bitsize == NULL))
-    sorry ("Support for HSA does not implement unhandled bit field reference "
-	   "such as %E", ref);
+    HSA_SORRY_ATV (EXPR_LOCATION (origref), "support for HSA does not "
+		   "implement unhandled bit field reference such as %E", ref);
 
   if (output_bitsize != NULL && output_bitpos != NULL)
     {
@@ -2014,8 +2051,9 @@ gen_hsa_insns_for_load (hsa_op_reg *dest, tree rhs, tree type, hsa_bb *hbb,
 	{
 	  if (dest->type != hsa_get_segment_addr_type (BRIG_SEGMENT_FLAT))
 	    {
-	      sorry ("Support for HSA does not implement conversion of %E to "
-		     "the requested non-pointer type.", rhs);
+	      HSA_SORRY_ATV (EXPR_LOCATION (rhs),
+			     "support for HSA does not implement conversion "
+			     "of %E to the requested non-pointer type.", rhs);
 	      return;
 	    }
 
@@ -2100,8 +2138,9 @@ gen_hsa_insns_for_load (hsa_op_reg *dest, tree rhs, tree type, hsa_bb *hbb,
       /* Handle load of a bit field.  */
       if (bitsize > 64)
 	{
-	  sorry ("Support for HSA does not implement load from a bit field "
-		 "bigger than 64 bits");
+	  HSA_SORRY_AT (EXPR_LOCATION (rhs),
+			"support for HSA does not implement load from a bit "
+			"field bigger than 64 bits");
 	  return;
 	}
 
@@ -2119,8 +2158,9 @@ gen_hsa_insns_for_load (hsa_op_reg *dest, tree rhs, tree type, hsa_bb *hbb,
 	}
     }
   else
-    sorry ("Support for HSA does not implement loading of expression %E",
-	   rhs);
+    HSA_SORRY_ATV
+      (EXPR_LOCATION (rhs),
+       "support for HSA does not implement loading of expression %E", rhs);
 }
 
 /* Return number of bits necessary for representation of a bit field,
@@ -2158,8 +2198,9 @@ gen_hsa_insns_for_store (tree lhs, hsa_op_base *src, hsa_bb *hbb,
   /* Handle store to a bit field.  */
   if (bitsize > 64)
     {
-      sorry ("Support for HSA does not implement store to a bit field "
-	     "bigger than 64 bits");
+      HSA_SORRY_AT (EXPR_LOCATION (lhs),
+		    "support for HSA does not implement store to a bit field "
+		    "bigger than 64 bits");
       return;
     }
 
@@ -2366,7 +2407,8 @@ gen_hsa_ctor_assignment (hsa_op_address *addr_lhs, tree rhs, hsa_bb *hbb)
 {
   if (vec_safe_length (CONSTRUCTOR_ELTS (rhs)))
     {
-      sorry ("Support for HSA does not implement load from constructor");
+      HSA_SORRY_AT (EXPR_LOCATION (rhs),
+		    "support for HSA does not implement load from constructor");
       return;
     }
 
@@ -2385,7 +2427,7 @@ gen_hsa_insns_for_single_assignment (tree lhs, tree rhs, hsa_bb *hbb,
   if (TREE_CODE (lhs) == SSA_NAME)
     {
       hsa_op_reg *dest = hsa_reg_for_gimple_ssa (lhs, ssa_map);
-      if (seen_error ())
+      if (hsa_seen_error ())
 	return;
 
       gen_hsa_insns_for_load (dest, rhs, TREE_TYPE (lhs), hbb, ssa_map);
@@ -2395,7 +2437,7 @@ gen_hsa_insns_for_single_assignment (tree lhs, tree rhs, hsa_bb *hbb,
     {
       /* Store to memory.  */
       hsa_op_base *src = hsa_reg_or_immed_for_gimple_op (rhs, hbb, ssa_map);
-      if (seen_error ())
+      if (hsa_seen_error ())
 	return;
 
       gen_hsa_insns_for_store (lhs, src, hbb, ssa_map);
@@ -2541,8 +2583,9 @@ gen_hsa_cmp_insn_from_gimple (enum tree_code code, tree lhs, tree rhs,
       break;
 
     default:
-      sorry ("Support for HSA does not implement comparison tree code %s\n",
-	     get_tree_code_name (code));
+      HSA_SORRY_ATV (EXPR_LOCATION (lhs),
+		     "support for HSA does not implement comparison tree "
+		     "code %s\n", get_tree_code_name (code));
       return;
     }
 
@@ -2648,8 +2691,9 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb,
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
-      sorry ("Support for HSA does not implement CEIL_DIV_EXPR, FLOOR_DIV_EXPR "
-	     "or ROUND_DIV_EXPR");
+      HSA_SORRY_AT (gimple_location (assign),
+		    "support for HSA does not implement CEIL_DIV_EXPR, "
+		    "FLOOR_DIV_EXPR or ROUND_DIV_EXPR");
       return;
     case TRUNC_MOD_EXPR:
       opcode = BRIG_OPCODE_REM;
@@ -2657,8 +2701,9 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb,
     case CEIL_MOD_EXPR:
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      sorry ("Support for HSA does not implement CEIL_MOD_EXPR, FLOOR_MOD_EXPR "
-	     "or ROUND_MOD_EXPR");
+      HSA_SORRY_AT (gimple_location (assign),
+		    "support for HSA does not implement CEIL_MOD_EXPR, "
+		    "FLOOR_MOD_EXPR or ROUND_MOD_EXPR");
       return;
     case NEGATE_EXPR:
       opcode = BRIG_OPCODE_NEG;
@@ -2850,8 +2895,9 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb,
       }
     default:
       /* Implement others as we come across them.  */
-      sorry ("Support for HSA does not implement operation %s",
-	     get_tree_code_name (code));
+      HSA_SORRY_ATV (gimple_location (assign),
+		     "support for HSA does not implement operation %s",
+		     get_tree_code_name (code));
       return;
     }
 
@@ -3012,13 +3058,15 @@ verify_function_arguments (tree decl)
 {
   if (DECL_STATIC_CHAIN (decl))
     {
-      sorry ("HSA does not support nested functions: %D", decl);
+      HSA_SORRY_ATV (EXPR_LOCATION (decl),
+		     "HSA does not support nested functions: %D", decl);
       return;
     }
   else if (!TYPE_ARG_TYPES (TREE_TYPE (decl)))
     {
-      sorry ("HSA does not support functions with variadic arguments "
-	     "(or unknown return type): %D", decl);
+      HSA_SORRY_ATV (EXPR_LOCATION (decl),
+		     "HSA does not support functions with variadic arguments "
+		     "(or unknown return type): %D", decl);
       return;
     }
 }
@@ -3034,7 +3082,7 @@ gen_hsa_insns_for_direct_call (gimple *stmt, hsa_bb *hbb,
 {
   tree decl = gimple_call_fndecl (stmt);
   verify_function_arguments (decl);
-  if (seen_error ())
+  if (hsa_seen_error ())
     return;
 
   hsa_insn_call *call_insn = new hsa_insn_call (decl);
@@ -3053,8 +3101,9 @@ gen_hsa_insns_for_direct_call (gimple *stmt, hsa_bb *hbb,
 
       if (AGGREGATE_TYPE_P (TREE_TYPE (parm)))
 	{
-	  sorry ("Support for HSA does not implement an aggregate argument "
-		 "in a function call");
+	  HSA_SORRY_AT (gimple_location (stmt),
+			"support for HSA does not "
+			"implement an aggregate argument in a function call");
 	  return;
 	}
 
@@ -3081,8 +3130,9 @@ gen_hsa_insns_for_direct_call (gimple *stmt, hsa_bb *hbb,
     {
       if (AGGREGATE_TYPE_P (result_type))
 	{
-	  sorry ("Support for HSA does not implement returning a value "
-		 "which is of an aggregate type: %T", result_type);
+	  HSA_SORRY_ATV (gimple_location (stmt),
+			 "support for HSA does not implement returning a value "
+			 "which is of an aggregate type %T", result_type);
 	  return;
 	}
 
@@ -3109,8 +3159,9 @@ gen_hsa_insns_for_direct_call (gimple *stmt, hsa_bb *hbb,
     {
       if (result)
 	{
-	  sorry ("Support for HSA does not implement an assignment of return "
-		 "value from a void function");
+	  HSA_SORRY_AT (gimple_location (stmt),
+			"support for HSA does not implement an assignment of "
+			"return value from a void function");
 	  return;
 	}
 
@@ -3137,8 +3188,9 @@ gen_hsa_insns_for_return (greturn *stmt, hsa_bb *hbb,
     {
       if (AGGREGATE_TYPE_P (TREE_TYPE (retval)))
 	{
-	  sorry ("HSA does not support return statement with an aggregate "
-		 "value type");
+	  HSA_SORRY_AT (gimple_location (stmt),
+			"HSA does not support return "
+			"statement with an aggregate value type");
 	  return;
 	}
 
@@ -3834,7 +3886,9 @@ get_address_from_value (tree val, hsa_bb *hbb, vec <hsa_op_reg_p> *ssa_map)
       /* Otherwise fall-through */
 
     default:
-      sorry ("Support for HSA does not implement memory access to %E", val);
+      HSA_SORRY_ATV (EXPR_LOCATION (val),
+		     "support for HSA does not implement memory access to %E",
+		     val);
       return new hsa_op_address (NULL, NULL, 0);
     }
 }
@@ -3968,15 +4022,17 @@ gen_hsa_insns_for_call (gimple *stmt, hsa_bb *hbb,
       tree function_decl = gimple_call_fndecl (stmt);
       if (function_decl == NULL_TREE)
 	{
-	  sorry ("HSA does not support indirect calls");
+	  HSA_SORRY_AT (gimple_location (stmt),
+			"support for HSA does not implement indirect calls");
 	  return;
 	}
 
       if (hsa_callable_function_p (function_decl))
         gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
       else if (!gen_hsa_insns_for_known_library_call (stmt, hbb, ssa_map))
-	sorry ("HSA does support only call for functions with 'hsafunc' "
-	       "attribute");
+	HSA_SORRY_AT (gimple_location (stmt),
+		      "HSA does support only call of functions within omp "
+		      "declare target or with 'hsafunc' attribute");
       return;
     }
 
@@ -4292,8 +4348,9 @@ specialop:
 
 	if (TREE_CODE (byte_size) != INTEGER_CST)
 	  {
-	    sorry ("Support for HSA does not implement __builtin_memcpy with "
-		   "a non constant size");
+	    HSA_SORRY_AT (gimple_location (stmt),
+			  "support for HSA does not implement __builtin_memcpy "
+			  "with a non constant size");
 	    return;
 	  }
 
@@ -4302,9 +4359,11 @@ specialop:
 	/* TODO: fallback to call to memcpy library function.  */
 	if (n > HSA_MEMORY_BUILTINS_LIMIT)
 	  {
-	    sorry ("Support for HSA does implement __builtin_memcpy with a size"
-		   " bigger than %u bytes, %u bytes are requested",
-		   HSA_MEMORY_BUILTINS_LIMIT, n);
+	    HSA_SORRY_ATV
+	      (gimple_location (stmt),
+	       "support for HSA does implement __builtin_memcpy with a size "
+	       "bigger than %u bytes, %u bytes are requested",
+	       HSA_MEMORY_BUILTINS_LIMIT, n);
 	    return;
 	  }
 
@@ -4329,8 +4388,10 @@ specialop:
 
 	if (TREE_CODE (c) != INTEGER_CST)
 	  {
-	    sorry ("Support for HSA does not implement __builtin_memset with "
-		   "a non constant byte value that should be written");
+	    HSA_SORRY_AT
+	      (gimple_location (stmt),
+	       "support for HSA does not implement __builtin_memset with a "
+	       "non constant byte value that should be written");
 	    return;
 	  }
 
@@ -4338,8 +4399,9 @@ specialop:
 
 	if (TREE_CODE (byte_size) != INTEGER_CST)
 	  {
-	    sorry ("Support for HSA does not implement __builtin_memset with "
-		   "a non constant size");
+	    HSA_SORRY_AT (gimple_location (stmt),
+			  "support for HSA does not implement "
+			  "__builtin_memset with a non constant size");
 	    return;
 	  }
 
@@ -4348,9 +4410,11 @@ specialop:
 	/* TODO: fallback to call to memset library function.  */
 	if (n > HSA_MEMORY_BUILTINS_LIMIT)
 	  {
-	    sorry ("Support for HSA does implement __builtin_memset with a size"
-		   " bigger than %u bytes, %u bytes are requested",
-		   HSA_MEMORY_BUILTINS_LIMIT, n);
+	    HSA_SORRY_ATV
+	      (gimple_location (stmt),
+	       "support for HSA does implement __builtin_memset with a size "
+	       "bigger than %u bytes, %u bytes are requested",
+	       HSA_MEMORY_BUILTINS_LIMIT, n);
 	    return;
 	  }
 
@@ -4369,8 +4433,9 @@ specialop:
 	break;
       }
     default:
-      sorry ("Support for HSA does not implement calls to builtin %D",
-	     gimple_call_fndecl (stmt));
+      HSA_SORRY_ATV (gimple_location (stmt),
+		     "support for HSA does not implement calls to builtin %D",
+		     gimple_call_fndecl (stmt));
       return;
     }
 }
@@ -4413,8 +4478,9 @@ gen_hsa_insns_for_gimple_stmt (gimple *stmt, hsa_bb *hbb,
     {
       tree label = gimple_label_label (as_a <glabel *> (stmt));
       if (FORCED_LABEL (label))
-	sorry ("Support for HSA does not implement gimple label with address "
-	       "taken");
+	HSA_SORRY_AT (gimple_location (stmt),
+		      "support for HSA does not implement gimple label with "
+		      "address taken");
 
       break;
     }
@@ -4429,8 +4495,9 @@ gen_hsa_insns_for_gimple_stmt (gimple *stmt, hsa_bb *hbb,
       break;
     }
     default:
-      sorry ("Support for HSA does not implement gimple statement %s",
-	     gimple_code_name[(int) gimple_code (stmt)]);
+      HSA_SORRY_ATV (gimple_location (stmt),
+		     "support for HSA does not implement gimple statement %s",
+		     gimple_code_name[(int) gimple_code (stmt)]);
     }
 }
 
@@ -4490,8 +4557,9 @@ gen_hsa_phi_from_gimple_phi (gimple *phi_stmt, hsa_bb *hbb,
 	    }
 	  else
 	    {
-	      sorry ("Support for HSA does not handle PHI nodes with constant "
-		     "address operands");
+	      HSA_SORRY_AT (gimple_location (phi_stmt),
+			    "support for HSA does not handle PHI nodes with "
+			    "constant address operands");
 	      return;
 	    }
 	}
@@ -4607,7 +4675,9 @@ gen_body_from_gimple (vec <hsa_op_reg_p> *ssa_map)
 	     to the same basic block.  */
 	  if (e->flags & EDGE_EH)
 	    {
-	      sorry ("Support for HSA does not implement exception handling");
+	      HSA_SORRY_AT
+		(UNKNOWN_LOCATION,
+		 "support for HSA does not implement exception handling");
 	      return;
 	    }
 	}
@@ -4621,7 +4691,7 @@ gen_body_from_gimple (vec <hsa_op_reg_p> *ssa_map)
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gen_hsa_insns_for_gimple_stmt (gsi_stmt (gsi), hbb, ssa_map);
-	  if (seen_error ())
+	  if (hsa_seen_error ())
 	    return;
 	}
     }
@@ -5061,16 +5131,16 @@ emit_hsa_module_variables (void)
 static void
 generate_hsa (bool kernel)
 {
+  vec <hsa_op_reg_p> ssa_map = vNULL;
+
   if (hsa_num_threads == NULL)
     emit_hsa_module_variables ();
 
+  hsa_init_data_for_cfun ();
   verify_function_arguments (cfun->decl);
-  if (seen_error ())
-    return;
-
-  vec <hsa_op_reg_p> ssa_map = vNULL;
+  if (hsa_seen_error ())
+    goto fail;
 
-  hsa_init_data_for_cfun ();
   hsa_cfun->decl = cfun->decl;
   hsa_cfun->kern_p = kernel;
 
@@ -5080,13 +5150,13 @@ generate_hsa (bool kernel)
   hsa_sanitize_name (hsa_cfun->name);
 
   gen_function_def_parameters (hsa_cfun, &ssa_map);
-  if (seen_error ())
+  if (hsa_seen_error ())
     goto fail;
 
   init_omp_in_prologue ();
 
   gen_body_from_gimple (&ssa_map);
-  if (seen_error ())
+  if (hsa_seen_error ())
     goto fail;
 
   if (hsa_cfun->kern_p)
diff --git a/gcc/hsa.c b/gcc/hsa.c
index ce8ae45..c938248 100644
--- a/gcc/hsa.c
+++ b/gcc/hsa.c
@@ -138,10 +138,8 @@ hsa_init_compilation_unit_data (void)
 void
 hsa_deinit_compilation_unit_data (void)
 {
-  if (!compilation_unit_data_initialized)
-    return;
-
-  delete hsa_global_variable_symbols;
+  if (compilation_unit_data_initialized)
+    delete hsa_global_variable_symbols;
 }
 
 /* Return true if we are generating large HSA machine model.  */
@@ -647,4 +645,12 @@ hsa_register_kernel (cgraph_node *gpu, cgraph_node *host)
   hsa_summaries->link_functions (gpu, host, HSA_KERNEL);
 }
 
+/* Return true if expansion of the current HSA function has already failed.  */
+
+bool
+hsa_seen_error (void)
+{
+  return hsa_cfun->seen_error;
+}
+
 #include "gt-hsa.h"
diff --git a/gcc/hsa.h b/gcc/hsa.h
index ce6414a..b400b39 100644
--- a/gcc/hsa.h
+++ b/gcc/hsa.h
@@ -973,6 +973,9 @@ public:
      OMP data size is necessary memory that is used for copying before
      a kernel dispatch.  */
   unsigned maximum_omp_data_size;
+
+  /* Return true if there's an HSA-specific warning already seen.  */
+  bool seen_error;
 };
 
 enum hsa_function_kind
@@ -1064,6 +1067,7 @@ char *hsa_brig_function_name (const char *p);
 const char *hsa_get_declaration_name (tree decl);
 void hsa_register_kernel (cgraph_node *host);
 void hsa_register_kernel (cgraph_node *gpu, cgraph_node *host);
+bool hsa_seen_error (void);
 
 /* In hsa-gen.c.  */
 void hsa_build_append_simple_mov (hsa_op_reg *, hsa_op_base *, hsa_bb *);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index bb0ffab..88c4143 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -758,6 +758,7 @@ struct gomp_device_descr
   void *(*dev2host_func) (int, void *, const void *, size_t);
   void *(*host2dev_func) (int, void *, const void *, size_t);
   void (*run_func) (int, void *, void *, const void *);
+  bool (*can_run_func) (void *);
 
   /* Splay tree containing information about mapped memory regions.  */
   struct splay_tree_s mem_map;
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index 76a3b45..60dac54 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -49,15 +49,60 @@ GOMP_OFFLOAD_version (void)
 
 static bool debug;
 
-/* Initialize debug according to the environment.  */
+/* Flag to decide if the runtime should suppress a possible fallback to host
+   execution.  */
+
+static bool suppress_host_fallback;
+
+/* Initialize debug and supress_host_fallback according to the environment.  */
 
 static void
-init_debug (void)
+init_enviroment_variables (void)
 {
   if (getenv ("HSA_DEBUG"))
     debug = true;
   else
     debug = false;
+
+  if (getenv ("HSA_SUPPRESS_HOST_FALLBACK"))
+    suppress_host_fallback = true;
+  else
+    suppress_host_fallback = false;
+}
+
+/* Print a debug message to stderr if DEBUG value is set to true.  */
+
+#define HSA_DEBUG(...) \
+  do \
+  { \
+    if (debug) \
+      { \
+	fprintf (stderr, "HSA debug: "); \
+	fprintf (stderr, __VA_ARGS__); \
+      } \
+  } \
+  while (false);
+
+/* Print HSA warning STR with an HSA STATUS code.  */
+
+static void
+hsa_warn (const char *str, hsa_status_t status)
+{
+  if (!debug)
+    return;
+
+  const char* hsa_error;
+  hsa_status_string (status, &hsa_error);
+
+  unsigned l = strlen (hsa_error);
+
+  char *err = GOMP_PLUGIN_malloc (sizeof (char) * l);
+  memcpy (err, hsa_error, l - 1);
+  err[l] = '\0';
+
+  fprintf (stderr, "HSA warning: %s (%s)\n", str, err);
+
+  free (err);
 }
 
 /* Report a fatal error STR together with the HSA error corresponding to STATUS
@@ -111,6 +156,8 @@ struct kernel_info
   /* Flag indicating whether the kernel has been initialized and all fields
      below it contain valid data.  */
   bool initialized;
+  /* Flag indicating that the kernel has a problem that blocks an execution.  */
+  bool initialization_failed;
   /* The object to be put into the dispatch queue.  */
   uint64_t object;
   /* Required size of kernel arguments.  */
@@ -175,6 +222,8 @@ struct agent_info
   /* Flag whether the HSA program that consists of all the modules has been
      finalized.  */
   bool prog_finalized;
+  /* Flag whether the program was finalized but with a failture.  */
+  bool prog_finalized_error;
   /* HSA executable - the finalized program that is used to locate kernels.  */
   hsa_executable_t executable;
 };
@@ -204,7 +253,6 @@ get_kernel_in_module (struct module_info *module, const char *kernel_name)
     if (strcmp (module->kernels[i].name, kernel_name) == 0)
       return &module->kernels[i];
 
-  GOMP_PLUGIN_fatal ("Could not find kernel dependency: %s\n", kernel_name);
   return NULL;
 }
 
@@ -271,17 +319,15 @@ init_hsa_context (void)
 
   if (hsa_context.initialized)
     return;
-  init_debug ();
+  init_enviroment_variables ();
   status = hsa_init ();
   if (status != HSA_STATUS_SUCCESS)
     hsa_fatal ("Run-time could not be initialized", status);
-  if (debug)
-    fprintf (stderr, "HSA run-time initialized\n");
+  HSA_DEBUG ("HSA run-time initialized\n");
   status = hsa_iterate_agents (count_gpu_agents, NULL);
   if (status != HSA_STATUS_SUCCESS)
     hsa_fatal ("HSA GPU devices could not be enumerated", status);
-  if (debug)
-    fprintf (stderr, "There are %i HSA GPU devices.\n", hsa_context.agent_count);
+  HSA_DEBUG ("There are %i HSA GPU devices.\n", hsa_context.agent_count);
 
   hsa_context.agents
     = GOMP_PLUGIN_malloc_cleared (hsa_context.agent_count
@@ -379,8 +425,7 @@ GOMP_OFFLOAD_init_device (int n)
   if (agent->kernarg_region.handle == (uint64_t) -1)
     GOMP_PLUGIN_fatal ("Could not find suitable memory region for kernel "
 		       "arguments");
-  if (debug)
-    fprintf (stderr, "HSA agent initialized, queue has id %llu\n",
+  HSA_DEBUG ("HSA agent initialized, queue has id %llu\n",
 	     (long long unsigned) agent->command_q->id);
   agent->initialized = true;
 }
@@ -431,10 +476,12 @@ remove_module_from_agent (struct agent_info *agent, struct module_info *module)
 static void
 destroy_hsa_program (struct agent_info *agent)
 {
+  if (!agent->prog_finalized || agent->prog_finalized_error)
+    return;
+
   hsa_status_t status;
 
-  if (debug)
-    fprintf (stderr, "Destroying the current HSA program.\n");
+  HSA_DEBUG ("Destroying the current HSA program.\n");
 
   status = hsa_executable_destroy (agent->executable);
   if (status != HSA_STATUS_SUCCESS)
@@ -473,8 +520,7 @@ GOMP_OFFLOAD_load_image (int ord, unsigned version  __attribute__ ((unused)),
   if (agent->prog_finalized)
     destroy_hsa_program (agent);
 
-  if (debug)
-    fprintf (stderr, "Encountered %d kernels in an image\n", kernel_count);
+  HSA_DEBUG ("Encountered %d kernels in an image\n", kernel_count);
   pair = GOMP_PLUGIN_malloc (kernel_count * sizeof (struct addr_pair));
   *target_table = pair;
   module = (struct module_info *)
@@ -523,19 +569,15 @@ create_and_finalize_hsa_program (struct agent_info *agent)
   if (pthread_mutex_lock (&agent->prog_mutex))
     GOMP_PLUGIN_fatal ("Could not lock an HSA agent program mutex");
   if (agent->prog_finalized)
-    {
-      if (pthread_mutex_unlock (&agent->prog_mutex))
-	GOMP_PLUGIN_fatal ("Could not unlock an HSA agent program mutex");
-      return;
-    }
+    goto final;
 
   status = hsa_ext_program_create (HSA_MACHINE_MODEL_LARGE, HSA_PROFILE_FULL,
 				   HSA_DEFAULT_FLOAT_ROUNDING_MODE_DEFAULT,
 				   NULL, &prog_handle);
   if (status != HSA_STATUS_SUCCESS)
     hsa_fatal ("Could not create an HSA program", status);
-  if (debug)
-    fprintf (stderr, "Created a finalizer program\n");
+
+  HSA_DEBUG ("Created a finalized program\n");
 
   struct module_info *module = agent->first_module;
   while (module)
@@ -544,8 +586,6 @@ create_and_finalize_hsa_program (struct agent_info *agent)
 					  module->image_desc->brig_module);
       if (status != HSA_STATUS_SUCCESS)
 	hsa_fatal ("Could not add a module to the HSA program", status);
-      if (debug)
-	fprintf (stderr, "Added module %i to the HSA program\n", mi);
       module = module->next;
       mi++;
     }
@@ -558,9 +598,12 @@ create_and_finalize_hsa_program (struct agent_info *agent)
 				    HSA_CODE_OBJECT_TYPE_PROGRAM,
 				    &code_object);
   if (status != HSA_STATUS_SUCCESS)
-    hsa_fatal ("Finalization of the HSA program failed", status);
-  if (debug)
-    fprintf (stderr, "Finalization done\n");
+    {
+      hsa_warn ("Finalization of the HSA program failed", status);
+      goto failure;
+    }
+
+  HSA_DEBUG ("Finalization done\n");
   hsa_ext_program_destroy (prog_handle);
 
   status = hsa_executable_create(HSA_PROFILE_FULL, HSA_EXECUTABLE_STATE_UNFROZEN,
@@ -576,9 +619,17 @@ create_and_finalize_hsa_program (struct agent_info *agent)
   if (status != HSA_STATUS_SUCCESS)
     hsa_fatal ("Could not freeze the HSA executable", status);
 
-  if (debug)
-    fprintf (stderr, "Froze HSA executable with the finalized code object\n");
+  HSA_DEBUG ("Froze HSA executable with the finalized code object\n");
+
+  /* If all goes good, jump to final.  */
+  goto final;
+
+failure:
+  agent->prog_finalized_error = true;
+
+final:
   agent->prog_finalized = true;
+
   if (pthread_mutex_unlock (&agent->prog_mutex))
     GOMP_PLUGIN_fatal ("Could not unlock an HSA agent program mutex");
 }
@@ -626,8 +677,7 @@ create_kernel_dispatch (struct kernel_info *kernel, unsigned omp_data_size)
 static void
 release_kernel_dispatch (struct hsa_kernel_dispatch *shadow)
 {
-  if (debug)
-    fprintf (stderr, "Released kernel dispatch: %p has value: %lu (%p)\n",
+  HSA_DEBUG ("Released kernel dispatch: %p has value: %lu (%p)\n",
 	     shadow, shadow->debug, (void *)shadow->debug);
 
   hsa_memory_free (shadow->kernarg_address);
@@ -657,9 +707,11 @@ init_single_kernel (struct kernel_info *kernel, unsigned *max_omp_data_size)
   status = hsa_executable_get_symbol (agent->executable, NULL, kernel->name,
 				      agent->id, 0, &kernel_symbol);
   if (status != HSA_STATUS_SUCCESS)
-    hsa_fatal ("Could not find symbol for kernel in the code object", status);
-  if (debug)
-    fprintf (stderr, "Located kernel %s\n", kernel->name);
+    {
+      hsa_warn ("Could not find symbol for kernel in the code object", status);
+      goto failure;
+    }
+  HSA_DEBUG ("Located kernel %s\n", kernel->name);
   status = hsa_executable_symbol_get_info
     (kernel_symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_OBJECT, &kernel->object);
   if (status != HSA_STATUS_SUCCESS)
@@ -678,22 +730,18 @@ init_single_kernel (struct kernel_info *kernel, unsigned *max_omp_data_size)
     (kernel_symbol, HSA_EXECUTABLE_SYMBOL_INFO_KERNEL_PRIVATE_SEGMENT_SIZE,
      &kernel->private_segment_size);
   if (status != HSA_STATUS_SUCCESS)
-    hsa_fatal ("Could not get info about kernel private segment size", status);
-
-  if (debug)
-    {
-      fprintf (stderr, "Kernel structure for %s fully initialized with "
-	       "following segment sizes: \n",
-	       kernel->name);
-      fprintf (stderr, "  group_segment_size: %u\n",
-	       (unsigned) kernel->group_segment_size);
-      fprintf (stderr, "  private_segment_size: %u\n",
-	       (unsigned) kernel->private_segment_size);
-      fprintf (stderr, "  kernarg_segment_size: %u\n",
-	       (unsigned) kernel->kernarg_segment_size);
-      fprintf (stderr, "  omp_data_size: %u\n",
-	       kernel->omp_data_size);
-    }
+    hsa_fatal ("Could not get info about kernel private segment size",
+	       status);
+
+  HSA_DEBUG ("Kernel structure for %s fully initialized with "
+	     "following segment sizes: \n", kernel->name);
+  HSA_DEBUG ("  group_segment_size: %u\n",
+	     (unsigned) kernel->group_segment_size);
+  HSA_DEBUG ("  private_segment_size: %u\n",
+	     (unsigned) kernel->private_segment_size);
+  HSA_DEBUG ("  kernarg_segment_size: %u\n",
+	     (unsigned) kernel->kernarg_segment_size);
+  HSA_DEBUG ("  omp_data_size: %u\n", kernel->omp_data_size);
 
   if (kernel->omp_data_size > *max_omp_data_size)
     *max_omp_data_size = kernel->omp_data_size;
@@ -704,8 +752,23 @@ init_single_kernel (struct kernel_info *kernel, unsigned *max_omp_data_size)
     {
       struct kernel_info *dependency = get_kernel_in_module
 	(module, kernel->dependencies[i]);
+
+      if (dependency == NULL)
+	{
+	  HSA_DEBUG ("Could not find a dependency for a kernel: %s, "
+		     "dependency name: %s\n", kernel->name,
+		     kernel->dependencies[i]);
+	  goto failure;
+	}
+
+
       init_single_kernel (dependency, max_omp_data_size);
     }
+
+  return;
+
+failure:
+  kernel->initialization_failed = true;
 }
 
 /* Indent stream F by INDENT spaces.  */
@@ -800,8 +863,8 @@ init_kernel (struct kernel_info *kernel)
      dispatch operation.  */
   init_single_kernel (kernel, &kernel->max_omp_data_size);
 
-  if (debug)
-    fprintf (stderr, "\n");
+  if (!kernel->initialization_failed)
+    HSA_DEBUG ("\n");
 
   kernel->initialized = true;
   if (pthread_mutex_unlock (&kernel->init_mutex))
@@ -840,8 +903,7 @@ parse_launch_attributes (const void *input,
       def->wdims[1] = 1;
       def->wdims[2] = 1;
       *result = def;
-      if (debug)
-	fprintf (stderr, "GOMP_OFFLOAD_run called with no launch attributes\n");
+      HSA_DEBUG ("GOMP_OFFLOAD_run called with no launch attributes\n");
       return true;
     }
 
@@ -854,13 +916,37 @@ parse_launch_attributes (const void *input,
   if (kla->gdims[0] == 0)
     return false;
 
-  if (debug)
-    fprintf (stderr, "GOMP_OFFLOAD_run called with grid size %u and group "
-	     "size %u\n", kla->gdims[0], kla->wdims[0]);
+  HSA_DEBUG ("GOMP_OFFLOAD_run called with grid size %u and group size %u\n",
+	     kla->gdims[0], kla->wdims[0]);
 
   return true;
 }
 
+/* Return true if the HSA runtime can run function FN_PTR.  */
+
+bool
+GOMP_OFFLOAD_can_run (void *fn_ptr)
+{
+  struct kernel_info *kernel = (struct kernel_info *) fn_ptr;
+  struct agent_info *agent = kernel->agent;
+  create_and_finalize_hsa_program (agent);
+
+  if (agent->prog_finalized_error)
+    goto failure;
+
+  init_kernel (kernel);
+  if (kernel->initialization_failed)
+    goto failure;
+
+  return true;
+
+failure:
+  if (suppress_host_fallback)
+    GOMP_PLUGIN_fatal ("HSA host fallback has been suppressed");
+  HSA_DEBUG ("HSA target cannot be launched, doing a host fallback\n");
+  return false;
+}
+
 /* Part of the libgomp plugin interface.  Run a kernel on a device N and pass
    the it an array of pointers in VARS as a parameter.  The kernel is
    identified by FN_PTR which must point to a kernel_info structure.  */
@@ -874,16 +960,18 @@ GOMP_OFFLOAD_run (int n, void *fn_ptr, void *vars, const void* kern_launch)
   const struct kernel_launch_attributes *kla;
   if (!parse_launch_attributes (kern_launch, &def, &kla))
     {
-      if (debug)
-	fprintf (stderr, "Will not run HSA kernel because the grid size is "
-		 "zero\n");
+      HSA_DEBUG ("Will not run HSA kernel because the grid size is zero\n");
       return;
     }
   if (pthread_rwlock_rdlock (&agent->modules_rwlock))
     GOMP_PLUGIN_fatal ("Unable to read-lock an HSA agent rwlock");
 
-  create_and_finalize_hsa_program (agent);
-  init_kernel (kernel) ;
+  if (!agent->initialized)
+    GOMP_PLUGIN_fatal ("Agent must be initialized");
+
+  if (!kernel->initialized)
+    GOMP_PLUGIN_fatal ("Called kernel must be initialized");
+
   struct hsa_kernel_dispatch *shadow = create_kernel_dispatch_recursive
     (kernel, kernel->max_omp_data_size);
 
@@ -894,8 +982,7 @@ GOMP_OFFLOAD_run (int n, void *fn_ptr, void *vars, const void* kern_launch)
     }
 
   uint64_t index = hsa_queue_add_write_index_release (agent->command_q, 1);
-  if (debug)
-    fprintf (stderr, "Got AQL index %llu\n", (long long int) index);
+  HSA_DEBUG ("Got AQL index %llu\n", (long long int) index);
 
   /* Wait until the queue is not full before writing the packet.   */
   while (index - hsa_queue_load_read_index_acquire(agent->command_q)
@@ -933,22 +1020,19 @@ GOMP_OFFLOAD_run (int n, void *fn_ptr, void *vars, const void* kern_launch)
   memcpy (shadow->kernarg_address + sizeof (vars), &shadow,
 	  sizeof (struct hsa_kernel_runtime *));
 
-  if (debug)
-    fprintf (stderr, "Copying kernel runtime pointer to kernarg_address\n");
+  HSA_DEBUG ("Copying kernel runtime pointer to kernarg_address\n");
 
   uint16_t header;
   header = HSA_PACKET_TYPE_KERNEL_DISPATCH << HSA_PACKET_HEADER_TYPE;
   header |= HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_ACQUIRE_FENCE_SCOPE;
   header |= HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_RELEASE_FENCE_SCOPE;
 
-  if (debug)
-    fprintf (stderr, "Going to dispatch kernel %s\n", kernel->name);
+  HSA_DEBUG ("Going to dispatch kernel %s\n", kernel->name);
 
   __atomic_store_n ((uint16_t*)(&packet->header), header, __ATOMIC_RELEASE);
   hsa_signal_store_release (agent->command_q->doorbell_signal, index);
 
-  if (debug)
-    fprintf (stderr, "Kernel dispatched, waiting for completion\n");
+  HSA_DEBUG ("Kernel dispatched, waiting for completion\n");
   hsa_signal_wait_acquire (s, HSA_SIGNAL_CONDITION_LT, 1,
 			   UINT64_MAX, HSA_WAIT_STATE_BLOCKED);
 
@@ -999,8 +1083,7 @@ GOMP_OFFLOAD_unload_image (int n, unsigned version  __attribute__ ((unused)),
   remove_module_from_agent (agent, module);
   destroy_module (module);
   free (module);
-  if (agent->prog_finalized)
-    destroy_hsa_program (agent);
+  destroy_hsa_program (agent);
   if (pthread_rwlock_unlock (&agent->modules_rwlock))
     GOMP_PLUGIN_fatal ("Unable to unlock an HSA agent rwlock");
 }
@@ -1027,8 +1110,7 @@ GOMP_OFFLOAD_fini_device (int n)
       free (module);
     }
   agent->first_module = NULL;
-  if (agent->prog_finalized)
-    destroy_hsa_program (agent);
+  destroy_hsa_program (agent);
 
   hsa_status_t status = hsa_queue_destroy (agent->command_q);
   if (status != HSA_STATUS_SUCCESS)
@@ -1037,7 +1119,7 @@ GOMP_OFFLOAD_fini_device (int n)
     GOMP_PLUGIN_fatal ("Failed to destroy an HSA agent program mutex");
   if (pthread_rwlock_destroy (&agent->modules_rwlock))
     GOMP_PLUGIN_fatal ("Failed to destroy an HSA agent rwlock");
-  agent->initialized =  false;
+  agent->initialized = false;
 }
 
 /* Part of the libgomp plugin interface.  Not implemented as it is not required
diff --git a/libgomp/target.c b/libgomp/target.c
index 7a60b66..a555c0f 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -945,6 +945,24 @@ gomp_fini_device (struct gomp_device_descr *devicep)
   devicep->is_initialized = false;
 }
 
+/* Execute a host function FN with HOSTADDRS.  */
+
+static void
+run_on_host (void (*fn) (void *), void **hostaddrs)
+{
+  struct gomp_thread old_thr, *thr = gomp_thread ();
+  old_thr = *thr;
+  memset (thr, '\0', sizeof (*thr));
+  if (gomp_places_list)
+    {
+      thr->place = old_thr.place;
+      thr->ts.place_partition_len = gomp_places_list_len;
+    }
+  fn (hostaddrs);
+  gomp_free_thread (thr);
+  *thr = old_thr;
+}
+
 /* Called when encountering a target directive.  If DEVICE
    is GOMP_DEVICE_ICV, it means use device-var ICV.  If it is
    GOMP_DEVICE_HOST_FALLBACK (or any value
@@ -966,17 +984,7 @@ GOMP_target (int device, void (*fn) (void *), const void *kernel_launch,
       || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
     {
       /* Host fallback.  */
-      struct gomp_thread old_thr, *thr = gomp_thread ();
-      old_thr = *thr;
-      memset (thr, '\0', sizeof (*thr));
-      if (gomp_places_list)
-	{
-	  thr->place = old_thr.place;
-	  thr->ts.place_partition_len = gomp_places_list_len;
-	}
-      fn (hostaddrs);
-      gomp_free_thread (thr);
-      *thr = old_thr;
+      run_on_host (fn, hostaddrs);
       return;
     }
 
@@ -1006,6 +1014,12 @@ GOMP_target (int device, void (*fn) (void *), const void *kernel_launch,
       fn_addr = (void *) tgt_fn->tgt_offset;
     }
 
+  if (devicep->can_run_func && !devicep->can_run_func (fn_addr))
+    {
+      run_on_host (fn, hostaddrs);
+      return;
+    }
+
   struct target_mem_desc *tgt_vars;
   if (devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
     tgt_vars = NULL;
@@ -1020,6 +1034,7 @@ GOMP_target (int device, void (*fn) (void *), const void *kernel_launch,
       thr->place = old_thr.place;
       thr->ts.place_partition_len = gomp_places_list_len;
     }
+
   devicep->run_func (devicep->target_id, fn_addr,
 		     tgt_vars ? (void *) tgt_vars->tgt_start : hostaddrs,
 		     kernel_launch);
@@ -1160,7 +1175,10 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (host2dev);
   device->capabilities = device->get_caps_func ();
   if (device->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
-    DLSYM (run);
+    {
+      DLSYM (run);
+      DLSYM (can_run);
+    }
   if (device->capabilities & GOMP_OFFLOAD_CAP_OPENACC_200)
     {
       if (!DLSYM_OPT (openacc.exec, openacc_parallel)
-- 
2.5.1

>From 35b9c822b935a9d10df2e1b93cc3179d9ca470f4 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Mon, 5 Oct 2015 16:39:12 +0200
Subject: [PATCH 2/9] HSA: Add loading of default BRIG shared libraries

libgomp/ChangeLog:

2015-10-06  Martin Liska  <mliska@suse.cz>

	* plugin/plugin-hsa.c (struct brig_library_info): New structure.
	(struct agent_info): Add BRIG shared libraries.
	(add_shared_library): New function.
	(release_agent_shared_libraries): Likewise.
	(create_and_finalize_hsa_program): Add loading of shared
	libraries.
	(GOMP_OFFLOAD_fini_device): Release allocated memory.

gcc/ChangeLog:

2015-10-06  Martin Liska  <mliska@suse.cz>

	* hsa-gen.c (gen_hsa_insns_for_call): Expand unsupported
	builtins to calls that are going to be resolved by BRIG shared
	libraries.
---
 gcc/hsa-gen.c               |  35 ++++----------
 libgomp/plugin/plugin-hsa.c | 109 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 112 insertions(+), 32 deletions(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index fb17a25..3dd7613 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -4348,22 +4348,15 @@ specialop:
 
 	if (TREE_CODE (byte_size) != INTEGER_CST)
 	  {
-	    HSA_SORRY_AT (gimple_location (stmt),
-			  "support for HSA does not implement __builtin_memcpy "
-			  "with a non constant size");
+	    gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
 	    return;
 	  }
 
 	unsigned n = tree_to_uhwi (byte_size);
 
-	/* TODO: fallback to call to memcpy library function.  */
 	if (n > HSA_MEMORY_BUILTINS_LIMIT)
 	  {
-	    HSA_SORRY_ATV
-	      (gimple_location (stmt),
-	       "support for HSA does implement __builtin_memcpy with a size "
-	       "bigger than %u bytes, %u bytes are requested",
-	       HSA_MEMORY_BUILTINS_LIMIT, n);
+	    gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
 	    return;
 	  }
 
@@ -4388,10 +4381,7 @@ specialop:
 
 	if (TREE_CODE (c) != INTEGER_CST)
 	  {
-	    HSA_SORRY_AT
-	      (gimple_location (stmt),
-	       "support for HSA does not implement __builtin_memset with a "
-	       "non constant byte value that should be written");
+	    gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
 	    return;
 	  }
 
@@ -4399,22 +4389,15 @@ specialop:
 
 	if (TREE_CODE (byte_size) != INTEGER_CST)
 	  {
-	    HSA_SORRY_AT (gimple_location (stmt),
-			  "support for HSA does not implement "
-			  "__builtin_memset with a non constant size");
+	    gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
 	    return;
 	  }
 
 	unsigned n = tree_to_uhwi (byte_size);
 
-	/* TODO: fallback to call to memset library function.  */
 	if (n > HSA_MEMORY_BUILTINS_LIMIT)
 	  {
-	    HSA_SORRY_ATV
-	      (gimple_location (stmt),
-	       "support for HSA does implement __builtin_memset with a size "
-	       "bigger than %u bytes, %u bytes are requested",
-	       HSA_MEMORY_BUILTINS_LIMIT, n);
+	    gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
 	    return;
 	  }
 
@@ -4433,10 +4416,10 @@ specialop:
 	break;
       }
     default:
-      HSA_SORRY_ATV (gimple_location (stmt),
-		     "support for HSA does not implement calls to builtin %D",
-		     gimple_call_fndecl (stmt));
-      return;
+      {
+	gen_hsa_insns_for_direct_call (stmt, hbb, ssa_map);
+	return;
+      }
     }
 }
 
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index 60dac54..f1c0427 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -7,7 +7,7 @@
 #include "hsa.h"
 #include "hsa-traits.h"
 #include "hsa_ext_finalize.h"
-
+#include "dlfcn.h"
 
 /* Part of the libgomp plugin interface.  Return the name of the accelerator,
    which is "hsa".  */
@@ -70,19 +70,28 @@ init_enviroment_variables (void)
     suppress_host_fallback = false;
 }
 
-/* Print a debug message to stderr if DEBUG value is set to true.  */
+/* Print a logging message with PREFIX to stderr if HSA_DEBUG value
+   is set to true.  */
 
-#define HSA_DEBUG(...) \
+#define HSA_LOG(prefix, ...) \
   do \
   { \
     if (debug) \
       { \
-	fprintf (stderr, "HSA debug: "); \
+	fprintf (stderr, prefix); \
 	fprintf (stderr, __VA_ARGS__); \
       } \
   } \
   while (false);
 
+/* Print a debugging message to stderr.  */
+
+#define HSA_DEBUG(...) HSA_LOG ("HSA debug: ", __VA_ARGS__)
+
+/* Print a warning message to stderr.  */
+
+#define HSA_WARNING(...) HSA_LOG ("HSA warning: ", __VA_ARGS__)
+
 /* Print HSA warning STR with an HSA STATUS code.  */
 
 static void
@@ -190,6 +199,14 @@ struct module_info
   struct kernel_info kernels[];
 };
 
+/* Information about shared brig library.  */
+
+struct brig_library_info
+{
+  char *file_name;
+  hsa_ext_module_t image;
+};
+
 /* Description of an HSA GPU agent and the program associated with it.  */
 
 struct agent_info
@@ -226,6 +243,10 @@ struct agent_info
   bool prog_finalized_error;
   /* HSA executable - the finalized program that is used to locate kernels.  */
   hsa_executable_t executable;
+  /* List of BRIG libraries.  */
+  struct brig_library_info **brig_libraries;
+  /* Number of loaded shared BRIG libraries.  */
+  unsigned brig_libraries_count;
 };
 
 /* Information about the whole HSA environment and all of its agents.  */
@@ -557,6 +578,50 @@ GOMP_OFFLOAD_load_image (int ord, unsigned version  __attribute__ ((unused)),
   return kernel_count;
 }
 
+/* Add a shared BRIG library from a FILE_NAME to an AGENT.  */
+
+static struct brig_library_info *
+add_shared_library (const char *file_name, struct agent_info *agent)
+{
+  struct brig_library_info *library = NULL;
+
+  void *f = dlopen (file_name, RTLD_NOW);
+  void *start = dlsym (f, "__brig_start");
+  void *end = dlsym (f, "__brig_end");
+
+  if (start == NULL || end == NULL)
+    return NULL;
+
+  unsigned size = end - start;
+  char *buf = (char *) malloc (size);
+  memcpy (buf, start, size);
+
+  library = GOMP_PLUGIN_malloc (sizeof (struct agent_info));
+  library->file_name = (char *) GOMP_PLUGIN_malloc
+    ((strlen (file_name) + 1) * sizeof (char));
+  strcpy (library->file_name, file_name);
+  library->image = (hsa_ext_module_t) buf;
+
+  return library;
+}
+
+/* Release memory used for BRIG shared libraries that correspond
+   to an AGENT.  */
+
+static void
+release_agent_shared_libraries (struct agent_info *agent)
+{
+  for (unsigned i = 0; i < agent->brig_libraries_count; i++)
+    if (agent->brig_libraries[i])
+      {
+	free (agent->brig_libraries[i]->file_name);
+	free (agent->brig_libraries[i]->image);
+	free (agent->brig_libraries[i]);
+      }
+
+  free (agent->brig_libraries);
+}
+
 /* Create and finalize the program consisting of all loaded modules.  */
 
 static void
@@ -582,13 +647,42 @@ create_and_finalize_hsa_program (struct agent_info *agent)
   struct module_info *module = agent->first_module;
   while (module)
     {
-      status = hsa_ext_program_add_module(prog_handle,
-					  module->image_desc->brig_module);
+      status = hsa_ext_program_add_module (prog_handle,
+					   module->image_desc->brig_module);
       if (status != HSA_STATUS_SUCCESS)
 	hsa_fatal ("Could not add a module to the HSA program", status);
       module = module->next;
       mi++;
     }
+
+  /* Load all shared libraries.  */
+  const char *libraries[] = { "libhsamath.so", "libhsastd.so" };
+  const unsigned libraries_count = sizeof (libraries) / sizeof (const char *);
+
+  agent->brig_libraries_count = libraries_count;
+  agent->brig_libraries = GOMP_PLUGIN_malloc_cleared
+    (sizeof (struct brig_library_info) * libraries_count);
+
+  for (unsigned i = 0; i < libraries_count; i++)
+    {
+      struct brig_library_info *library = add_shared_library (libraries[i],
+							      agent);
+      if (library == NULL)
+	{
+	  HSA_WARNING ("Could not open a shared BRIG library: %s\n",
+		       libraries[i]);
+	  continue;
+	}
+
+      status = hsa_ext_program_add_module (prog_handle, library->image);
+      if (status != HSA_STATUS_SUCCESS)
+	hsa_warn ("Could not add a shared BRIG library the HSA program",
+		  status);
+      else
+	HSA_DEBUG ("a shared BRIG library has been added to a program: %s\n",
+		   libraries[i]);
+    }
+
   hsa_ext_control_directives_t control_directives;
   memset (&control_directives, 0, sizeof (control_directives));
   hsa_code_object_t code_object;
@@ -625,6 +719,7 @@ create_and_finalize_hsa_program (struct agent_info *agent)
   goto final;
 
 failure:
+  release_agent_shared_libraries (agent);
   agent->prog_finalized_error = true;
 
 final:
@@ -1112,6 +1207,8 @@ GOMP_OFFLOAD_fini_device (int n)
   agent->first_module = NULL;
   destroy_hsa_program (agent);
 
+  release_agent_shared_libraries (agent);
+
   hsa_status_t status = hsa_queue_destroy (agent->command_q);
   if (status != HSA_STATUS_SUCCESS)
     hsa_fatal ("Error destroying command queue", status);
-- 
2.5.1

>From 06a75aff1f695f128f49664af027eeadab255caa Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 7 Oct 2015 16:50:04 +0200
Subject: [PATCH 3/9] HSA: change linkage for a function that cannot be
 emitted.

gcc/ChangeLog:

2015-10-07  Martin Liska  <mliska@suse.cz>

	* hsa-brig.c (emit_function_declaration): Return pointer to
	BrigDirectiveExecutable structure.
	(hsa_brig_emit_function): Save the structure for all emitted
	declarations.
	(hsa_output_brig): Fix function linkage, if needed.
	* hsa-gen.c (HSA_SORRY_AT{V}): Put all failed functions
	to a set.
	* hsa.h (hsa_failed_functions): New global variable.
	(hsa_fail_cfun): New function.
	* hsa.c (hsa_failed_functions): Define the variable.
	(hsa_fail_cfun): New function.
---
 gcc/hsa-brig.c | 30 +++++++++++++++++++++++-------
 gcc/hsa-gen.c  |  4 ++--
 gcc/hsa.c      | 17 +++++++++++++++++
 gcc/hsa.h      |  3 +++
 4 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/gcc/hsa-brig.c b/gcc/hsa-brig.c
index 53c9d32..29ddbba 100644
--- a/gcc/hsa-brig.c
+++ b/gcc/hsa-brig.c
@@ -132,7 +132,7 @@ static bool brig_initialized = false;
 static hash_map<tree, BrigCodeOffset32_t> *function_offsets;
 
 /* Set of emitted function declarations.  */
-static hash_set <tree> *emitted_declarations;
+static hash_map <tree, BrigDirectiveExecutable *> *emitted_declarations;
 
 /* List of sbr instructions.  */
 static vec <hsa_insn_sbr *> *switch_instructions;
@@ -1110,15 +1110,18 @@ emit_queued_operands (void)
 
 /* Emit directives describing the function that is used for
 a function declaration.  */
-static void
+
+static BrigDirectiveExecutable *
 emit_function_declaration (tree decl)
 {
   hsa_function_representation *f = hsa_generate_function_declaration (decl);
 
-  emit_function_directives (f, true);
+  BrigDirectiveExecutable *e = emit_function_directives (f, true);
   emit_queued_operands ();
 
   delete f;
+
+  return e;
 }
 
 /* Emit an HSA memory instruction and all necessary directives, schedule
@@ -1881,17 +1884,17 @@ hsa_brig_emit_function (void)
     function_offsets = new hash_map<tree, BrigCodeOffset32_t> ();
 
   if (!emitted_declarations)
-    emitted_declarations = new hash_set<tree> ();
+    emitted_declarations = new hash_map <tree, BrigDirectiveExecutable *> ();
 
   for (unsigned i = 0; i < hsa_cfun->called_functions.length (); i++)
     {
       tree called = hsa_cfun->called_functions[i];
 
       /* If the function has no definition, emit a declaration.  */
-      if (!emitted_declarations->contains (called))
+      if (!emitted_declarations->get (called))
 	{
-	  emit_function_declaration (called);
-	  emitted_declarations->add (called);
+	  BrigDirectiveExecutable *e = emit_function_declaration (called);
+	  emitted_declarations->put (called, e);
 	}
     }
 
@@ -2280,6 +2283,19 @@ hsa_output_brig (void)
       code_ref->ref = htole32 (*func_offset);
     }
 
+  /* Iterate all function declarations and if we meet a function that should
+     have module linkage and we are unable to emit HSAIL for the function,
+     then change the linkage to program linkage.  Doing so, we will emit
+     a valid BRIG image.  */
+  if (hsa_failed_functions != NULL && emitted_declarations != NULL)
+    for (hash_map <tree, BrigDirectiveExecutable *>::iterator it =
+	 emitted_declarations->begin (); it != emitted_declarations->end ();
+	 ++it)
+      {
+	if (hsa_failed_functions->contains ((*it).first))
+	  (*it).second->linkage = BRIG_LINKAGE_PROGRAM;
+      }
+
   saved_section = in_section;
 
   switch_to_section (get_section (BRIG_ELF_SECTION_NAME, SECTION_NOTYPE, NULL));
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 3dd7613..ae03361 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -84,7 +84,7 @@ along with GCC; see the file COPYING3.  If not see
 #define HSA_SORRY_ATV(location, message, ...) \
   do \
   { \
-    hsa_cfun->seen_error = true; \
+    hsa_fail_cfun (); \
     if (warning_at (EXPR_LOCATION (hsa_cfun->decl), OPT_Whsa, \
 		    HSA_SORRY_MSG)) \
       inform (location, message, ##__VA_ARGS__); \
@@ -96,7 +96,7 @@ along with GCC; see the file COPYING3.  If not see
 #define HSA_SORRY_AT(location, message) \
   do \
   { \
-    hsa_cfun->seen_error = true; \
+    hsa_fail_cfun (); \
     if (warning_at (EXPR_LOCATION (hsa_cfun->decl), OPT_Whsa, \
 		    HSA_SORRY_MSG)) \
       inform (location, message); \
diff --git a/gcc/hsa.c b/gcc/hsa.c
index c938248..5aa40fc 100644
--- a/gcc/hsa.c
+++ b/gcc/hsa.c
@@ -107,6 +107,9 @@ hsa_summary_t *hsa_summaries = NULL;
 /* HSA number of threads.  */
 hsa_symbol *hsa_num_threads = NULL;
 
+/* HSA function that cannot be expanded to HSAIL.  */
+hash_set <tree> *hsa_failed_functions = NULL;
+
 /* True if compilation unit-wide data are already allocated and initialized.  */
 static bool compilation_unit_data_initialized;
 
@@ -140,6 +143,9 @@ hsa_deinit_compilation_unit_data (void)
 {
   if (compilation_unit_data_initialized)
     delete hsa_global_variable_symbols;
+
+  if (hsa_failed_functions)
+    delete hsa_failed_functions;
 }
 
 /* Return true if we are generating large HSA machine model.  */
@@ -653,4 +659,15 @@ hsa_seen_error (void)
   return hsa_cfun->seen_error;
 }
 
+/* Mark current HSA function as failed.  */
+
+void
+hsa_fail_cfun (void)
+{
+  if (hsa_failed_functions == NULL)
+    hsa_failed_functions = new hash_set <tree> ();
+  hsa_failed_functions->add (hsa_cfun->decl);
+  hsa_cfun->seen_error = true;
+}
+
 #include "gt-hsa.h"
diff --git a/gcc/hsa.h b/gcc/hsa.h
index b400b39..4861e00 100644
--- a/gcc/hsa.h
+++ b/gcc/hsa.h
@@ -1043,6 +1043,8 @@ extern hash_map <tree, vec <char *> *> *hsa_decl_kernel_dependencies;
 extern hsa_summary_t *hsa_summaries;
 extern hsa_symbol *hsa_num_threads;
 extern unsigned hsa_kernel_calls_counter;
+extern hash_set <tree> *hsa_failed_functions;
+
 bool hsa_callable_function_p (tree fndecl);
 void hsa_init_compilation_unit_data (void);
 void hsa_deinit_compilation_unit_data (void);
@@ -1068,6 +1070,7 @@ const char *hsa_get_declaration_name (tree decl);
 void hsa_register_kernel (cgraph_node *host);
 void hsa_register_kernel (cgraph_node *gpu, cgraph_node *host);
 bool hsa_seen_error (void);
+void hsa_fail_cfun (void);
 
 /* In hsa-gen.c.  */
 void hsa_build_append_simple_mov (hsa_op_reg *, hsa_op_base *, hsa_bb *);
-- 
2.5.1

>From 9ae73202db1fd631d7ac4b56263cf5c91b256be6 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 7 Oct 2015 17:07:32 +0200
Subject: [PATCH 4/9] HSA: surrender HSA emission if an error is seen.

gcc/ChangeLog:

2015-10-07  Martin Liska  <mliska@suse.cz>

	* hsa-gen.c (gen_hsa_insns_for_operation_assignment): Surrender
	if an error is seen.
---
 gcc/hsa-gen.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index ae03361..f831611 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -2910,6 +2910,9 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb,
   hsa_op_with_type *op2 = rhs2 != NULL_TREE ?
     hsa_reg_or_immed_for_gimple_op (rhs2, hbb, ssa_map) : NULL;
 
+  if (hsa_seen_error ())
+    return;
+
   switch (rhs_class)
     {
     case GIMPLE_TERNARY_RHS:
-- 
2.5.1

>From d6cfc72c388553316619d9d51b25c24539ca34d3 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 7 Oct 2015 22:14:19 +0200
Subject: [PATCH 5/9] HSA: preserve HSA function names and visibility

gcc/ChangeLog:

2015-10-08  Martin Liska  <mliska@suse.cz>

	* hsa-brig.c (hsa_output_kernel_mapping): Change type of kernel
	dependencies container.
	* hsa-gen.c (has_host_function_p): New function.
	(hsa_generate_function_declaration): Emit host implementation of
	a function declaration.
	(generate_hsa): Likewise.
	(hsa_get_gpu_function): Remove unused function.
	* hsa.c (hsa_add_kernel_dependency): Change type of a function
	argument.
	* hsa.h: Likewise.
	* ipa-hsa.c (process_hsa_functions): Copy visibility from
	a cloned function.
---
 gcc/hsa-brig.c |  7 ++++---
 gcc/hsa-gen.c  | 39 +++++++++++++++++++--------------------
 gcc/hsa.c      | 12 ++++++------
 gcc/hsa.h      |  4 ++--
 gcc/ipa-hsa.c  |  2 ++
 5 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/gcc/hsa-brig.c b/gcc/hsa-brig.c
index 29ddbba..b6eabfd 100644
--- a/gcc/hsa-brig.c
+++ b/gcc/hsa-brig.c
@@ -2057,10 +2057,11 @@ hsa_output_kernel_mapping (tree brig_decl)
       vec<constructor_elt, va_gc> *kernel_dependencies_vec = NULL;
       if (hsa_decl_kernel_dependencies)
 	{
-	  vec<char *> **slot = hsa_decl_kernel_dependencies->get (kernel);
+	  vec<const char *> **slot;
+	  slot = hsa_decl_kernel_dependencies->get (kernel);
 	  if (slot)
 	    {
-	      vec <char *> *dependencies = *slot;
+	      vec <const char *> *dependencies = *slot;
 	      count = dependencies->length ();
 
 	      kernel_dependencies_vector_type = build_array_type
@@ -2069,7 +2070,7 @@ hsa_output_kernel_mapping (tree brig_decl)
 
 	      for (unsigned j = 0; j < count; j++)
 		{
-		  char *d = (*dependencies)[j];
+		  const char *d = (*dependencies)[j];
 		  len = strlen (d);
 		  tree dependency_name = build_string (len, d);
 		  TREE_TYPE (dependency_name) = build_array_type
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index f831611..cf36882 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -713,19 +713,6 @@ get_symbol_for_decl (tree decl)
   return sym;
 }
 
-/* For a given function declaration, return a GPU function
-   of the function.  */
-
-static tree
-hsa_get_gpu_function (tree decl)
-{
-  hsa_function_summary *s = hsa_summaries->get (cgraph_node::get_create (decl));
-  gcc_assert (s->kind != HSA_NONE);
-  gcc_assert (!s->gpu_implementation_p);
-
-  return s->binded_function->decl;
-}
-
 /* For a given HSA function declaration, return a host
    function declaration.  */
 
@@ -739,6 +726,15 @@ hsa_get_host_function (tree decl)
   return s->binded_function->decl;
 }
 
+/* Return true if function DECL has a host equivalent function.  */
+
+static bool
+has_host_function_p (tree decl)
+{
+  hsa_function_summary *s = hsa_summaries->get (cgraph_node::get_create (decl));
+  return s != NULL && s->kind != HSA_NONE && s->gpu_implementation_p;
+}
+
 /* Create a spill symbol of type TYPE.  */
 
 hsa_symbol *
@@ -4322,10 +4318,9 @@ specialop:
 	called = TREE_OPERAND (called, 0);
 	gcc_checking_assert (TREE_CODE (called) == FUNCTION_DECL);
 
-	const char *name = hsa_get_declaration_name
-	  (hsa_get_gpu_function (called));
-	hsa_add_kernel_dependency (hsa_cfun->decl,
-				   hsa_brig_function_name (name));
+	char *name = xstrdup (hsa_get_declaration_name (called));
+	hsa_add_kernel_dependency
+	  (hsa_cfun->decl, hsa_brig_function_name (name));
 	gen_hsa_insns_for_kernel_call (hbb, as_a <gcall *> (stmt));
 
 	break;
@@ -4832,9 +4827,12 @@ hsa_generate_function_declaration (tree decl)
 {
   hsa_function_representation *fun = XCNEW (hsa_function_representation);
 
+  tree host_decl = has_host_function_p (decl) ? hsa_get_host_function (decl) :
+    decl;
+
   fun->declaration_p = true;
   fun->decl = decl;
-  fun->name = xstrdup (hsa_get_declaration_name (decl));
+  fun->name = xstrdup (hsa_get_declaration_name (host_decl));
   hsa_sanitize_name (fun->name);
 
   gen_function_decl_parameters (fun, decl);
@@ -5118,6 +5116,7 @@ static void
 generate_hsa (bool kernel)
 {
   vec <hsa_op_reg_p> ssa_map = vNULL;
+  tree host_decl = NULL_TREE;
 
   if (hsa_num_threads == NULL)
     emit_hsa_module_variables ();
@@ -5130,9 +5129,9 @@ generate_hsa (bool kernel)
   hsa_cfun->decl = cfun->decl;
   hsa_cfun->kern_p = kernel;
 
+  host_decl = hsa_get_host_function (current_function_decl);
   ssa_map.safe_grow_cleared (SSANAMES (cfun)->length ());
-  hsa_cfun->name
-    = xstrdup (hsa_get_declaration_name (current_function_decl));
+  hsa_cfun->name = xstrdup (hsa_get_declaration_name (host_decl));
   hsa_sanitize_name (hsa_cfun->name);
 
   gen_function_def_parameters (hsa_cfun, &ssa_map);
diff --git a/gcc/hsa.c b/gcc/hsa.c
index 5aa40fc..7da7b6c 100644
--- a/gcc/hsa.c
+++ b/gcc/hsa.c
@@ -96,7 +96,7 @@ static GTY (()) vec<hsa_decl_kernel_map_element, va_gc> *hsa_decl_kernel_mapping
 
 /* Mapping between decls and corresponding HSA kernels
    called by the function.  */
-hash_map <tree, vec <char *> *> *hsa_decl_kernel_dependencies;
+hash_map <tree, vec <const char *> *> *hsa_decl_kernel_dependencies;
 
 /* Hash function to lookup a symbol for a decl.  */
 hash_table <hsa_free_symbol_hasher> *hsa_global_variable_symbols;
@@ -564,16 +564,16 @@ hsa_free_decl_kernel_mapping (void)
 /* Add new kernel dependency.  */
 
 void
-hsa_add_kernel_dependency (tree caller, char *called_function)
+hsa_add_kernel_dependency (tree caller, const char *called_function)
 {
   if (hsa_decl_kernel_dependencies == NULL)
-    hsa_decl_kernel_dependencies = new hash_map<tree, vec<char *> *> ();
+    hsa_decl_kernel_dependencies = new hash_map<tree, vec<const char *> *> ();
 
-  vec <char *> *s = NULL;
-  vec <char *> **slot = hsa_decl_kernel_dependencies->get (caller);
+  vec <const char *> *s = NULL;
+  vec <const char *> **slot = hsa_decl_kernel_dependencies->get (caller);
   if (slot == NULL)
     {
-      s = new vec <char *> ();
+      s = new vec <const char *> ();
       hsa_decl_kernel_dependencies->put (caller, s);
     }
   else
diff --git a/gcc/hsa.h b/gcc/hsa.h
index 4861e00..98d70e0 100644
--- a/gcc/hsa.h
+++ b/gcc/hsa.h
@@ -1039,7 +1039,7 @@ hsa_summary_t::link_functions (cgraph_node *gpu, cgraph_node *host,
 /* in hsa.c */
 extern struct hsa_function_representation *hsa_cfun;
 extern hash_table <hsa_free_symbol_hasher> *hsa_global_variable_symbols;
-extern hash_map <tree, vec <char *> *> *hsa_decl_kernel_dependencies;
+extern hash_map <tree, vec <const char *> *> *hsa_decl_kernel_dependencies;
 extern hsa_summary_t *hsa_summaries;
 extern hsa_symbol *hsa_num_threads;
 extern unsigned hsa_kernel_calls_counter;
@@ -1063,7 +1063,7 @@ tree hsa_get_decl_kernel_mapping_decl (unsigned i);
 char *hsa_get_decl_kernel_mapping_name (unsigned i);
 unsigned hsa_get_decl_kernel_mapping_omp_size (unsigned i);
 void hsa_free_decl_kernel_mapping (void);
-void hsa_add_kernel_dependency (tree caller, char *called_function);
+void hsa_add_kernel_dependency (tree caller, const char *called_function);
 void hsa_sanitize_name (char *p);
 char *hsa_brig_function_name (const char *p);
 const char *hsa_get_declaration_name (tree decl);
diff --git a/gcc/ipa-hsa.c b/gcc/ipa-hsa.c
index d87a17b..0c072da 100644
--- a/gcc/ipa-hsa.c
+++ b/gcc/ipa-hsa.c
@@ -101,6 +101,7 @@ process_hsa_functions (void)
 	{
 	  cgraph_node *clone = node->create_virtual_clone
 	    (vec <cgraph_edge *> (), NULL, NULL, "hsa");
+	  TREE_PUBLIC (clone->decl) = TREE_PUBLIC (node->decl);
 
 	  clone->force_output = true;
 	  hsa_summaries->link_functions (clone, node, s->kind);
@@ -114,6 +115,7 @@ process_hsa_functions (void)
 	{
 	  cgraph_node *clone = node->create_virtual_clone
 	    (vec <cgraph_edge *> (), NULL, NULL, "hsa");
+	  TREE_PUBLIC (clone->decl) = TREE_PUBLIC (node->decl);
 
 	  if (!cgraph_local_p (node))
 	    clone->force_output = true;
-- 
2.5.1

>From 55b82750b576588883d41407bf96e3cd1adc4c62 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Thu, 8 Oct 2015 10:06:25 +0200
Subject: [PATCH 6/9] HSA: simplify LTO partitioning and improve kernel
 dependencies resolution.

gcc/lto/ChangeLog:

2015-10-08  Martin Liska  <mliska@suse.cz>

	* lto-partition.c (add_symbol_to_partition_1): Simplify a much
	partitioning of HSA symbols.

libgomp/ChangeLog:

2015-10-08  Martin Liska  <mliska@suse.cz>

	* plugin/plugin-hsa.c (get_kernel_for_agent): New function.
	(init_single_kernel): Use it.
	(create_kernel_dispatch_recursive): Dtto.
---
 gcc/lto/lto-partition.c     | 30 ------------------------------
 libgomp/plugin/plugin-hsa.c | 30 ++++++++++++++++--------------
 2 files changed, 16 insertions(+), 44 deletions(-)

diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 01a60b2..9e0b95d 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -196,36 +196,6 @@ add_symbol_to_partition_1 (ltrans_partition part, symtab_node *node)
 			 "adding an HSA function (host/gpu) to the "
 			 "partition: %s\n",
 			 s->binded_function->name ());
-
-	      ipa_ref *ref;
-
-	      /* Add all parents nodes that have HSA type.  */
-	      for (unsigned i = 0; node->iterate_referring (i, ref); i++)
-		{
-		  cgraph_node *r = dyn_cast <cgraph_node *> (ref->referring);
-		  if (r && hsa_summaries->get (r)->kind != HSA_NONE)
-		    {
-		      add_symbol_to_partition_1 (part, r);
-		      if (symtab->dump_file)
-			fprintf (symtab->dump_file,
-				 "adding an HSA referring node: %s\n",
-				 r->name ());
-		    }
-		}
-
-	      /* Add all children nodes that have HSA type.  */
-	      for (unsigned i = 0; node->iterate_reference (i, ref); i++)
-		{
-		  cgraph_node *r = dyn_cast <cgraph_node *> (ref->referred);
-		  if (r && hsa_summaries->get (r)->kind != HSA_NONE)
-		    {
-		      add_symbol_to_partition_1 (part, r);
-		      if (symtab->dump_file)
-			fprintf (symtab->dump_file,
-				 "adding an HSA referred symbol: %s\n",
-				 r->name ());
-		    }
-		}
 	    }
 	}
     }
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index f1c0427..ed3573f 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -265,14 +265,21 @@ struct hsa_context_info
 
 static struct hsa_context_info hsa_context;
 
-/* Find kernel in MODULE by name provided in KERNEL_NAME.  */
+/* Find kernel for an AGENT by name provided in KERNEL_NAME.  */
 
 static struct kernel_info *
-get_kernel_in_module (struct module_info *module, const char *kernel_name)
+get_kernel_for_agent (struct agent_info *agent, const char *kernel_name)
 {
-  for (unsigned i = 0; i < module->kernel_count; i++)
-    if (strcmp (module->kernels[i].name, kernel_name) == 0)
-      return &module->kernels[i];
+  struct module_info *module = agent->first_module;
+
+  while (module)
+    {
+      for (unsigned i = 0; i < module->kernel_count; i++)
+	if (strcmp (module->kernels[i].name, kernel_name) == 0)
+	  return &module->kernels[i];
+
+      module = module->next;
+    }
 
   return NULL;
 }
@@ -841,12 +848,10 @@ init_single_kernel (struct kernel_info *kernel, unsigned *max_omp_data_size)
   if (kernel->omp_data_size > *max_omp_data_size)
     *max_omp_data_size = kernel->omp_data_size;
 
-  /* FIXME: do not consider all kernels to live in a same module.  */
-  struct module_info *module = kernel->agent->first_module;
   for (unsigned i = 0; i < kernel->dependencies_count; i++)
     {
-      struct kernel_info *dependency = get_kernel_in_module
-	(module, kernel->dependencies[i]);
+      struct kernel_info *dependency = get_kernel_for_agent
+	(agent, kernel->dependencies[i]);
 
       if (dependency == NULL)
 	{
@@ -917,9 +922,6 @@ static struct hsa_kernel_dispatch *
 create_kernel_dispatch_recursive (struct kernel_info *kernel,
 				  unsigned omp_data_size)
 {
-  // TODO: find correct module
-  struct module_info *module = kernel->agent->first_module;
-
   struct hsa_kernel_dispatch *shadow = create_kernel_dispatch (kernel,
 							       omp_data_size);
   shadow->omp_num_threads = 64;
@@ -927,8 +929,8 @@ create_kernel_dispatch_recursive (struct kernel_info *kernel,
 
   for (unsigned i = 0; i < kernel->dependencies_count; i++)
     {
-      struct kernel_info *dependency = get_kernel_in_module
-	(module, kernel->dependencies[i]);
+      struct kernel_info *dependency = get_kernel_for_agent
+	(kernel->agent, kernel->dependencies[i]);
       shadow->children_dispatches[i] = create_kernel_dispatch_recursive
 	(dependency, omp_data_size);
     }
-- 
2.5.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]