Hello.

Following patch set enhances back-end, it adds support for SBR instructions and
it fixed many issues spotted in GCC's test suite. Patches have been just applied
to HSA branch:

a73d92c HSA: add support for SBR instruction.
6485fbf HSA: fix issues in GIMPLE switch expansion.
b73698c HSA: fix an HSA predicate.
df466a1 HSA: fix ICE in compilation of a vector test.
1b2c8f0 HSA: add support for empty ctors.
6702754 HSA: fix mem{cpy,set}
0bf687e HSA: fix rotate expansion with a constant first argument.
8c7999d HSA: fix emission of atomic insns.
7c7c57a HSA: sorry in case of complex recursive edges presented in CFG.
b79576f HSA: add seen_error guard to assignment emission.
7808c7e HSA: handle CTORs and verify function arguments.

Thanks,
Martin
>From a73d92c322fd0327d43c632adff03c145f34c759 Mon Sep 17 00:00:00 2001
From: marxin <mli...@suse.cz>
Date: Tue, 22 Sep 2015 15:17:51 +0200
Subject: [PATCH 01/12] HSA: add support for SBR instruction.

gcc/ChangeLog:

2015-09-14  Martin Liska  <mli...@suse.cz>

	* hsa-brig.c (emit_unconditional_jump): New function.
	(emit_switch_insn): Likewise.
	(emit_insn): Add case for newly added hsa_insn_sbr.
	(perhaps_emit_branch): Handle switch statements.
	(hsa_brig_emit_function): Likewise.
	* hsa-dump.c (dump_hsa_insn): Likewise.
	(dump_hsa_bb): In case of switch, do not dump edges.
	* hsa-gen.c (hsa_init_data_for_cfun): Initialize new object allocator.
	(hsa_deinit_data_for_cfun): Delete it.
	(hsa_insn_sbr::hsa_insn_sbr): New ctor.
	(hsa_insn_sbr::operator new): New operator.
	(hsa_insn_sbr::redirect_label): New function.
	(HSA_MAXIMUM_SBR_LABELS): New macro definition.
	(get_switch_high): New function.
	(get_switch_low): Likewise.
	(get_switch_size): Likewise.
	(gen_hsa_insns_for_switch_stmt): New function.
	(gen_hsa_insns_for_gimple_stmt): Handle GIMPLE_SWITCH.
	(transformable_switch_to_sbr_p): New function.
	(convert_switch_statements): Use the function.
	* hsa-regalloc.c (naive_process_phi): Fix jump table of a switch if
	we split an edge.
	* hsa.c (hsa_opcode_op_output_p): Handle BRIG_OPCODE_SBR.
	* hsa.h (hsa_insn_sbr): New class.
---
 gcc/hsa-brig.c     | 122 +++++++++++++++++++++++++++++++-------
 gcc/hsa-dump.c     |  21 +++++++
 gcc/hsa-gen.c      | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/hsa-regalloc.c |  12 +++-
 gcc/hsa.c          |   1 +
 gcc/hsa.h          |  43 ++++++++++++++
 6 files changed, 347 insertions(+), 22 deletions(-)

diff --git a/gcc/hsa-brig.c b/gcc/hsa-brig.c
index 3f5ba0f..510496d 100644
--- a/gcc/hsa-brig.c
+++ b/gcc/hsa-brig.c
@@ -134,6 +134,9 @@ static hash_map<tree, BrigCodeOffset32_t> *function_offsets;
 /* Set of emitted function declarations.  */
 static hash_set <tree> *emitted_declarations;
 
+/* List of sbr instructions.  */
+static vec <hsa_insn_sbr *> *switch_instructions;
+
 struct function_linkage_pair
 {
   function_linkage_pair (tree decl, unsigned int off):
@@ -1384,7 +1387,7 @@ emit_branch_insn (hsa_insn_br *br)
   repr.base.base.kind = htole16 (BRIG_KIND_INST_BR);
   repr.base.opcode = htole16 (br->opcode);
   repr.width = BRIG_WIDTH_1;
-  /* For Conditional jumps the type is always B1 */
+  /* For Conditional jumps the type is always B1.  */
   repr.base.type = htole16 (BRIG_TYPE_B1);
 
   operand_offsets[0] = htole32 (enqueue_op (br->get_op (0)));
@@ -1404,11 +1407,74 @@ emit_branch_insn (hsa_insn_br *br)
   repr.base.operands = htole32 (brig_data.add (&byteCount, sizeof (byteCount)));
   brig_data.add (&operand_offsets, sizeof (operand_offsets));
   brig_data.round_size_up (4);
+  memset (&repr.reserved, 0, sizeof (repr.reserved));
+
+  brig_code.add (&repr, sizeof (repr));
+  brig_insn_count++;
+}
+
+/* Emit an HSA unconditional jump branching instruction that points to
+   a label REFERENCE.  */
+
+static void
+emit_unconditional_jump (hsa_op_code_ref *reference)
+{
+  struct BrigInstBr repr;
+  BrigOperandOffset32_t operand_offsets[1];
+  uint32_t byteCount;
+
+  repr.base.base.byteCount = htole16 (sizeof (repr));
+  repr.base.base.kind = htole16 (BRIG_KIND_INST_BR);
+  repr.base.opcode = htole16 (BRIG_OPCODE_BR);
+  repr.base.type = htole16 (BRIG_TYPE_NONE);
+  /* Direct branches to labels must be width(all).  */
+  repr.width = BRIG_WIDTH_ALL;
+
+  operand_offsets[0] = htole32 (enqueue_op (reference));
+  /* We have 1 operand so use 4 * 1 for the byteCount.  */
+  byteCount = htole32 (4 * 1);
+  repr.base.operands = htole32 (brig_data.add (&byteCount, sizeof (byteCount)));
+  brig_data.add (&operand_offsets, sizeof (operand_offsets));
+  brig_data.round_size_up (4);
+  memset (&repr.reserved, 0, sizeof (repr.reserved));
+  brig_code.add (&repr, sizeof (repr));
+  brig_insn_count++;
+}
+
+/* Emit an HSA switch jump instruction that uses a jump table to
+   jump to a destination label.  */
+
+static void
+emit_switch_insn (hsa_insn_sbr *sbr)
+{
+  struct BrigInstBr repr;
+  BrigOperandOffset32_t operand_offsets[2];
+  uint32_t byteCount;
+
+  gcc_assert (sbr->opcode == BRIG_OPCODE_SBR);
+  repr.base.base.byteCount = htole16 (sizeof (repr));
+  repr.base.base.kind = htole16 (BRIG_KIND_INST_BR);
+  repr.base.opcode = htole16 (sbr->opcode);
   repr.width = BRIG_WIDTH_1;
+  /* For Conditional jumps the type is always B1.  */
+  hsa_op_reg *index = as_a <hsa_op_reg *> (sbr->get_op (0));
+  repr.base.type = htole16 (index->type);
+  operand_offsets[0] = htole32 (enqueue_op (sbr->get_op (0)));
+  operand_offsets[1] = htole32 (enqueue_op (sbr->label_code_list));
+
+  /* We have 2 operands so use 4 * 2 for the byteCount.  */
+  byteCount = htole32 (4 * 2);
+  repr.base.operands = htole32 (brig_data.add (&byteCount, sizeof (byteCount)));
+  brig_data.add (&operand_offsets, sizeof (operand_offsets));
+  brig_data.round_size_up (4);
   memset (&repr.reserved, 0, sizeof (repr.reserved));
 
   brig_code.add (&repr, sizeof (repr));
   brig_insn_count++;
+
+  /* Emit jump to default label.  */
+  hsa_bb *hbb = hsa_bb_for_bb (sbr->default_bb);
+  emit_unconditional_jump (&hbb->label_ref);
 }
 
 /* Emit a HSA convert instruction and all necessary directives, schedule
@@ -1715,6 +1781,16 @@ emit_insn (hsa_insn_basic *insn)
       emit_branch_insn (br);
       return;
     }
+  if (hsa_insn_sbr *sbr = dyn_cast <hsa_insn_sbr *> (insn))
+    {
+      if (switch_instructions == NULL)
+	switch_instructions = new vec <hsa_insn_sbr *> ();
+
+      switch_instructions->safe_push (sbr);
+      emit_switch_insn (sbr);
+      return;
+    }
+
   if (hsa_insn_arg_block *arg_block = dyn_cast <hsa_insn_arg_block *> (insn))
     {
       emit_arg_block_insn (arg_block);
@@ -1746,13 +1822,16 @@ static void
 perhaps_emit_branch (basic_block bb, basic_block next_bb)
 {
   basic_block t_bb = NULL, ff = NULL;
-  struct BrigInstBr repr;
-  BrigOperandOffset32_t operand_offsets[1];
-  uint32_t byteCount;
 
   edge_iterator ei;
   edge e;
 
+  /* If the last instruction of BB is a switch, ignore emission of all
+     edges.  */
+  if (hsa_bb_for_bb (bb)->last_insn
+      && is_a <hsa_insn_sbr *> (hsa_bb_for_bb (bb)->last_insn))
+    return;
+
   FOR_EACH_EDGE (e, ei, bb->succs)
     if (e->flags & EDGE_TRUE_VALUE)
       {
@@ -1768,22 +1847,7 @@ perhaps_emit_branch (basic_block bb, basic_block next_bb)
   if (!ff || ff == next_bb || ff == EXIT_BLOCK_PTR_FOR_FN (cfun))
     return;
 
-  repr.base.base.byteCount = htole16 (sizeof (repr));
-  repr.base.base.kind = htole16 (BRIG_KIND_INST_BR);
-  repr.base.opcode = htole16 (BRIG_OPCODE_BR);
-  repr.base.type = htole16 (BRIG_TYPE_NONE);
-  /* Direct branches to labels must be width(all).  */
-  repr.width = BRIG_WIDTH_ALL;
-
-  operand_offsets[0] = htole32 (enqueue_op (&hsa_bb_for_bb (ff)->label_ref));
-  /* We have 1 operand so use 4 * 1 for the byteCount.  */
-  byteCount = htole32 (4 * 1);
-  repr.base.operands = htole32 (brig_data.add (&byteCount, sizeof (byteCount)));
-  brig_data.add (&operand_offsets, sizeof (operand_offsets));
-  brig_data.round_size_up (4);
-  memset (&repr.reserved, 0, sizeof (repr.reserved));
-  brig_code.add (&repr, sizeof (repr));
-  brig_insn_count++;
+  emit_unconditional_jump (&hsa_bb_for_bb (ff)->label_ref);
 }
 
 /* Emit the a function with name NAME to the various brig sections.  */
@@ -1836,6 +1900,24 @@ hsa_brig_emit_function (void)
   perhaps_emit_branch (prev_bb, NULL);
   ptr_to_fndir->nextModuleEntry = brig_code.total_size;
 
+  /* Fill up label references for all sbr instructions.  */
+  if (switch_instructions)
+    {
+      for (unsigned i = 0; i < switch_instructions->length (); i++)
+	{
+	  hsa_insn_sbr *sbr = (*switch_instructions)[i];
+	  for (unsigned j = 0; j < sbr->jump_table.length (); j++)
+	    {
+	      hsa_bb *hbb = hsa_bb_for_bb (sbr->jump_table[j]);
+	      sbr->label_code_list->offsets[j] =
+		hbb->label_ref.directive_offset;
+	    }
+	}
+    }
+
+  delete switch_instructions;
+  switch_instructions = NULL;
+
   emit_queued_operands ();
 }
 
diff --git a/gcc/hsa-dump.c b/gcc/hsa-dump.c
index 5e0d0ed..db44347 100644
--- a/gcc/hsa-dump.c
+++ b/gcc/hsa-dump.c
@@ -916,6 +916,23 @@ dump_hsa_insn (FILE *f, hsa_insn_basic *insn, int *indent)
 	  }
       fprintf (f, "BB %i\n", hsa_bb_for_bb (target)->index);
     }
+  else if (is_a <hsa_insn_sbr *> (insn))
+    {
+      hsa_insn_sbr *sbr = as_a <hsa_insn_sbr *> (insn);
+
+      fprintf (f, "%s ", hsa_opcode_name (sbr->opcode));
+      dump_hsa_reg (f, as_a <hsa_op_reg *> (sbr->get_op (0)));
+      fprintf (f, ", [");
+
+      for (unsigned i = 0; i < sbr->jump_table.length (); i++)
+	{
+	  fprintf (f, "BB %i", hsa_bb_for_bb (sbr->jump_table[i])->index);
+	  if (i != sbr->jump_table.length () - 1)
+	    fprintf (f, ", ");
+	}
+
+      fprintf (f, "]\n");
+    }
   else if (is_a <hsa_insn_arg_block *> (insn))
     {
       hsa_insn_arg_block *arg_block = as_a <hsa_insn_arg_block *> (insn);
@@ -1008,6 +1025,9 @@ dump_hsa_bb (FILE *f, hsa_bb *hbb)
   for (insn = hbb->first_insn; insn; insn = insn->next)
     dump_hsa_insn (f, insn, &indent);
 
+  if (hbb->last_insn && is_a <hsa_insn_sbr *> (hbb->last_insn))
+    goto exit;
+
   FOR_EACH_EDGE (e, ei, hbb->bb->succs)
     if (e->flags & EDGE_TRUE_VALUE)
       {
@@ -1037,6 +1057,7 @@ dump_hsa_bb (FILE *f, hsa_bb *hbb)
 	   && hbb->last_insn->opcode != BRIG_OPCODE_RET)
     fprintf (f, "  WARNING: Fall through to a BB with no aux!\n");
 
+exit:
   fprintf (f, "\n");
 }
 
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 34cbe42..7822def 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -154,6 +154,7 @@ static object_allocator<hsa_insn_signal> *hsa_allocp_inst_signal;
 static object_allocator<hsa_insn_seg> *hsa_allocp_inst_seg;
 static object_allocator<hsa_insn_cmp> *hsa_allocp_inst_cmp;
 static object_allocator<hsa_insn_br> *hsa_allocp_inst_br;
+static object_allocator<hsa_insn_sbr> *hsa_allocp_inst_sbr;
 static object_allocator<hsa_insn_call> *hsa_allocp_inst_call;
 static object_allocator<hsa_insn_arg_block> *hsa_allocp_inst_arg_block;
 static object_allocator<hsa_insn_comment> *hsa_allocp_inst_comment;
@@ -265,6 +266,8 @@ hsa_init_data_for_cfun ()
     = new object_allocator<hsa_insn_cmp> ("HSA comparison instructions");
   hsa_allocp_inst_br
     = new object_allocator<hsa_insn_br> ("HSA branching instructions");
+  hsa_allocp_inst_sbr
+    = new object_allocator<hsa_insn_sbr> ("HSA switch branching instructions");
   hsa_allocp_inst_call
     = new object_allocator<hsa_insn_call> ("HSA call instructions");
   hsa_allocp_inst_arg_block
@@ -332,6 +335,7 @@ hsa_deinit_data_for_cfun (void)
   delete hsa_allocp_inst_seg;
   delete hsa_allocp_inst_cmp;
   delete hsa_allocp_inst_br;
+  delete hsa_allocp_inst_sbr;
   delete hsa_allocp_inst_call;
   delete hsa_allocp_inst_arg_block;
   delete hsa_allocp_inst_comment;
@@ -1203,6 +1207,37 @@ hsa_insn_br::operator new (size_t)
   return hsa_allocp_inst_br->vallocate ();
 }
 
+/* Constructor of class representing instruction for switch jump, CTRL is
+   the index register.  */
+
+hsa_insn_sbr::hsa_insn_sbr (hsa_op_reg *index, unsigned jump_count)
+: hsa_insn_basic (1, BRIG_OPCODE_SBR, BRIG_TYPE_B1, index)
+{
+  width = BRIG_WIDTH_1;
+  jump_table = vNULL;
+  default_bb = NULL;
+  label_code_list = new hsa_op_code_list (jump_count);
+}
+
+/* New operator to allocate switch branch instruction from pool alloc.  */
+
+void *
+hsa_insn_sbr::operator new (size_t)
+{
+  return hsa_allocp_inst_sbr->vallocate ();
+}
+
+/* Replace all occurrences of OLD_BB with NEW_BB in the statements
+   jump table.  */
+
+void
+hsa_insn_sbr::replace_all_labels (basic_block old_bb, basic_block new_bb)
+{
+  for (unsigned i = 0; i < jump_table.length (); i++)
+    if (jump_table[i] == old_bb)
+      jump_table[i] = new_bb;
+}
+
 /* Constructor of comparison instructin.  CMP is the comparison operation and T
    is the result type.  */
 
@@ -2796,6 +2831,108 @@ gen_hsa_insns_for_cond_stmt (gimple *cond, hsa_bb *hbb,
   hbb->append_insn (cbr);
 }
 
+/* Maximum number of elements in a jump table for an HSA SBR instruction.  */
+
+#define HSA_MAXIMUM_SBR_LABELS	16
+
+/* Return lowest value of a switch S that is handled in a non-default
+   label.  */
+
+static tree
+get_switch_low (gswitch *s)
+{
+  unsigned labels = gimple_switch_num_labels (s);
+  gcc_checking_assert (labels >= 1);
+
+  return CASE_LOW (gimple_switch_label (s, 1));
+}
+
+/* Return highest value of a switch S that is handled in a non-default
+   label.  */
+
+static tree
+get_switch_high (gswitch *s)
+{
+  unsigned labels = gimple_switch_num_labels (s);
+
+  /* Compare last label to maximum number of labels.  */
+  tree label = gimple_switch_label (s, labels - 1);
+  tree low = CASE_LOW (label);
+  tree high = CASE_HIGH (label);
+
+  return high != NULL_TREE ? high : low;
+}
+
+static tree
+get_switch_size (gswitch *s)
+{
+  return int_const_binop (MINUS_EXPR, get_switch_high (s), get_switch_low (s));
+}
+
+/* Generate HSA instructions for a given gimple switch.
+   Instructions will be appended to HBB and SSA_MAP maps gimple SSA
+   names to HSA pseudo registers.  */
+
+static void
+gen_hsa_insns_for_switch_stmt (gswitch *s, hsa_bb *hbb,
+			       vec <hsa_op_reg_p> *ssa_map)
+{
+  function *func = DECL_STRUCT_FUNCTION (current_function_decl);
+  tree index_tree = gimple_switch_index (s);
+  tree lowest = get_switch_low (s);
+
+  hsa_op_reg *index = hsa_reg_for_gimple_ssa (index_tree, ssa_map);
+  hsa_op_reg *sub_index = new hsa_op_reg (index->type);
+  hbb->append_insn (new hsa_insn_basic (3, BRIG_OPCODE_SUB, sub_index->type,
+					sub_index, index,
+					new hsa_op_immed (lowest)));
+
+  if (hsa_needs_cvt (BRIG_TYPE_U64, sub_index->type))
+    {
+      hsa_op_reg *sub_index_cvt = new hsa_op_reg (BRIG_TYPE_U64);
+      hbb->append_insn (new hsa_insn_basic (2, BRIG_OPCODE_CVT,
+					    sub_index_cvt->type,
+					    sub_index_cvt, sub_index));
+
+      sub_index = sub_index_cvt;
+    }
+
+  unsigned labels = gimple_switch_num_labels (s);
+  unsigned HOST_WIDE_INT size = tree_to_uhwi (get_switch_size (s));
+
+  hsa_insn_sbr *sbr = new hsa_insn_sbr (sub_index, size + 1);
+  tree default_label = gimple_switch_default_label (s);
+  basic_block default_label_bb = label_to_block_fn
+    (func, CASE_LABEL (default_label));
+
+  sbr->default_bb = default_label_bb;
+
+  /* Prepare array with default label destination.  */
+  for (unsigned HOST_WIDE_INT i = 0; i <= size; i++)
+    sbr->jump_table.safe_push (default_label_bb);
+
+  /* Iterate all labels and fill up the jump table.  */
+  for (unsigned i = 1; i < labels; i++)
+    {
+      tree label = gimple_switch_label (s, i);
+      basic_block bb = label_to_block_fn (func, CASE_LABEL (label));
+
+      unsigned HOST_WIDE_INT sub_low = tree_to_uhwi
+	(int_const_binop (MINUS_EXPR, CASE_LOW (label), lowest));
+
+      unsigned HOST_WIDE_INT sub_high = sub_low;
+      tree high = CASE_HIGH (label);
+      if (high != NULL)
+	sub_high = tree_to_uhwi (int_const_binop (MINUS_EXPR, high, lowest));
+
+      for (unsigned HOST_WIDE_INT j = sub_low; j <= sub_high; j++)
+	sbr->jump_table[j] = bb;
+    }
+
+  hbb->append_insn (sbr);
+}
+
+
 /* Generate HSA instructions for a direct call instruction.
    Instructions will be appended to HBB, which also needs to be the
    corresponding structure to the basic_block of STMT. SSA_MAP maps gimple SSA
@@ -3923,6 +4060,11 @@ gen_hsa_insns_for_gimple_stmt (gimple *stmt, hsa_bb *hbb,
       hbb->append_insn (new hsa_insn_basic (0, BRIG_OPCODE_NOP));
       break;
     }
+    case GIMPLE_SWITCH:
+    {
+      gen_hsa_insns_for_switch_stmt (as_a <gswitch *> (stmt), hbb, ssa_map);
+      break;
+    }
     default:
       sorry ("Support for HSA does not implement gimple statement %s",
 	     gimple_code_name[(int) gimple_code (stmt)]);
@@ -4231,6 +4373,28 @@ hsa_generate_function_declaration (tree decl)
   return fun;
 }
 
+/* Return true if switch statement S can be transformed
+   to a SBR instruction in HSAIL.  */
+
+static bool
+transformable_switch_to_sbr_p (gswitch *s)
+{
+  /* Identify if a switch statement can be transformed to
+     SBR instruction, like:
+
+     sbr_u32 $s1 [@label1, @label2, @label3];
+  */
+
+  tree size = get_switch_size (s);
+  if (!tree_fits_uhwi_p (size))
+    return false;
+
+  if (tree_to_uhwi (size) > HSA_MAXIMUM_SBR_LABELS)
+    return false;
+
+  return true;
+}
+
 static void
 convert_switch_statements ()
 {
@@ -4250,9 +4414,13 @@ convert_switch_statements ()
 
     if (gimple_code (stmt) == GIMPLE_SWITCH)
       {
+	gswitch *s = as_a <gswitch *> (stmt);
+
+	if (transformable_switch_to_sbr_p (s))
+	  continue;
+
 	need_update = true;
 
-	gswitch *s = as_a <gswitch *> (stmt);
 	unsigned labels = gimple_switch_num_labels (s);
 	tree index = gimple_switch_index (s);
 	tree default_label = gimple_switch_default_label (s);
diff --git a/gcc/hsa-regalloc.c b/gcc/hsa-regalloc.c
index 6edf2ab..19ef354 100644
--- a/gcc/hsa-regalloc.c
+++ b/gcc/hsa-regalloc.c
@@ -94,7 +94,17 @@ naive_process_phi (hsa_insn_phi *phi)
       if (single_succ_p (e->src))
 	hbb = hsa_bb_for_bb (e->src);
       else
-	hbb = hsa_init_new_bb (split_edge (e));
+	{
+	  basic_block old_dest = e->dest;
+	  hbb = hsa_init_new_bb (split_edge (e));
+
+	  /* If switch insn used this edge, fix jump table.  */
+	  hsa_bb *source = hsa_bb_for_bb (e->src);
+	  hsa_insn_sbr *sbr;
+	  if (source->last_insn
+	      && (sbr = dyn_cast <hsa_insn_sbr *> (source->last_insn)))
+	    sbr->replace_all_labels (old_dest, hbb->bb);
+	}
 
       hsa_build_append_simple_mov (phi->dest, op, hbb);
     }
diff --git a/gcc/hsa.c b/gcc/hsa.c
index 8513322..1dbdcb4 100644
--- a/gcc/hsa.c
+++ b/gcc/hsa.c
@@ -168,6 +168,7 @@ hsa_opcode_op_output_p (int opcode, int opnum)
     {
     case HSA_OPCODE_PHI:
     case BRIG_OPCODE_CBR:
+    case BRIG_OPCODE_SBR:
     case BRIG_OPCODE_ST:
     case BRIG_OPCODE_SIGNALNORET:
       /* FIXME: There are probably missing cases here, double check.  */
diff --git a/gcc/hsa.h b/gcc/hsa.h
index 16fe310..3f0d122 100644
--- a/gcc/hsa.h
+++ b/gcc/hsa.h
@@ -446,6 +446,49 @@ is_a_helper <hsa_insn_br *>::test (hsa_insn_basic *p)
     || p->opcode == BRIG_OPCODE_CBR;
 }
 
+class hsa_bb;
+
+/* HSA instruction for swtich branche.  */
+
+class hsa_insn_sbr : public hsa_insn_basic
+{
+public:
+  hsa_insn_sbr (hsa_op_reg *index, unsigned jump_count);
+
+  void *operator new (size_t);
+
+  void replace_all_labels (basic_block old_bb, basic_block new_bb);
+
+  /* Width as described in HSA documentation.  */
+  BrigWidth8_t width;
+
+  /* Jump table.  */
+  vec <basic_block> jump_table;
+
+  /* Default label basic block.  */
+  basic_block default_bb;
+
+  /* Code list for label references.  */
+  hsa_op_code_list *label_code_list;
+
+private:
+  /* Make the default constructor inaccessible.  */
+  hsa_insn_sbr () : hsa_insn_basic (1, BRIG_OPCODE_SBR) {}
+  /* All objects are deallocated by destroying their pool, so make delete
+     inaccessible too.  */
+  void operator delete (void *) {}
+};
+
+/* Report whether P is a switch branching instruction.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <hsa_insn_sbr *>::test (hsa_insn_basic *p)
+{
+  return p->opcode == BRIG_OPCODE_SBR;
+}
+
 /* HSA instruction for comparisons.  */
 
 class hsa_insn_cmp : public hsa_insn_basic
-- 
2.5.1

>From 6485fbf1f2a934b23865a09d01b9ea7e0042290e Mon Sep 17 00:00:00 2001
From: marxin <mli...@suse.cz>
Date: Tue, 22 Sep 2015 15:18:43 +0200
Subject: [PATCH 02/12] HSA: fix issues in GIMPLE switch expansion.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (struct phi_definition): New structure.
	(convert_switch_statements): Handle properly preserving of PHI
	immediate values.
---
 gcc/hsa-gen.c | 133 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 99 insertions(+), 34 deletions(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 7822def..5226dd8 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -75,6 +75,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfghooks.h"
 #include "tree-cfg.h"
 #include "cfgloop.h"
+#include "cfganal.h"
 
 /* Following structures are defined in the final version
    of HSA specification.  */
@@ -4395,6 +4396,64 @@ transformable_switch_to_sbr_p (gswitch *s)
   return true;
 }
 
+/* Structure hold connection between PHI nodes and immediate
+   values hold by there nodes.  */
+
+struct phi_definition
+{
+  phi_definition (unsigned phi_i, unsigned label_i, tree imm):
+    phi_index (phi_i), label_index (label_i), phi_value (imm)
+  {}
+
+  unsigned phi_index;
+  unsigned label_index;
+  tree phi_value;
+};
+
+/* Function transforms GIMPLE SWITCH statements to a series of IF statements.
+   Let's assume following example:
+
+L0:
+   switch (index)
+     case C1:
+L1:    hard_work_1 ();
+       break;
+     case C2..C3:
+L2:    hard_work_2 ();
+       break;
+     default:
+LD:    hard_work_3 ();
+       break;
+
+  The tranformation encompases following steps:
+    1) all immediate values used by edges coming from the switch basic block
+       are saved
+    2) all these edges are removed
+    3) the switch statement (in L0) is replaced by:
+	 if (index == C1)
+	   goto L1;
+	 else
+	   goto L1';
+
+    4) newly created basic block Lx' is used for generation of
+       a next condition
+    5) else branch of the last condition goes to LD
+    6) fix all immediate values in PHI nodes that were propagated though
+       edges that were removed in step 2
+
+  Note: if a case is made by a range C1..C2, then process
+	following transformation:
+
+  switch_cond_op1 = C1 <= index;
+  switch_cond_op2 = index <= C2;
+  switch_cond_and = switch_cond_op1 & switch_cond_op2;
+  if (switch_cond_and != 0)
+    goto Lx;
+  else
+    goto Ly;
+
+*/
+
 static void
 convert_switch_statements ()
 {
@@ -4416,6 +4475,7 @@ convert_switch_statements ()
       {
 	gswitch *s = as_a <gswitch *> (stmt);
 
+	/* If the switch can utilize SBR insn, skip the statement.  */
 	if (transformable_switch_to_sbr_p (s))
 	  continue;
 
@@ -4428,29 +4488,43 @@ convert_switch_statements ()
 	  (func, CASE_LABEL (default_label));
 	basic_block cur_bb = bb;
 
-	hash_map<basic_block, tree> phi_defs;
+	auto_vec <edge> new_edges;
+	auto_vec <phi_definition *> phi_todo_list;
 
-	/* Remove all edges for the current basic block.  */
-	for (int i = EDGE_COUNT (bb->succs) - 1; i >= 0; i--)
+	/* Investigate all labels that and PHI nodes in these edges which
+	   should be fixed after we add new collection of edges.  */
+	for (unsigned i = 0; i < labels; i++)
 	  {
-	    edge e = EDGE_SUCC (bb, i);
-	    gphi_iterator phi_gsi = gsi_start_phis (EDGE_SUCC (bb, i)->dest);
+	    tree label = gimple_switch_label (s, i);
+	    basic_block label_bb = label_to_block_fn (func, CASE_LABEL (label));
+	    edge e = find_edge (bb, label_bb);
+	    gphi_iterator phi_gsi;
 
 	    /* Save PHI definitions that will be destroyed because of an edge
 	       is going to be removed.  */
-	    if (!gsi_end_p (phi_gsi))
+	    unsigned phi_index = 0;
+	    for (phi_gsi = gsi_start_phis (e->dest);
+		 !gsi_end_p (phi_gsi); gsi_next (&phi_gsi))
 	      {
 		gphi *phi = phi_gsi.phi ();
-		for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
+		for (unsigned j = 0; j < gimple_phi_num_args (phi); j++)
 		  {
-		    if (gimple_phi_arg_edge (phi, i) == e)
+		    if (gimple_phi_arg_edge (phi, j) == e)
 		      {
-			phi_defs.put (e->dest, gimple_phi_arg_def (phi, i));
+			tree imm = gimple_phi_arg_def (phi, j);
+			phi_todo_list.safe_push
+			  (new phi_definition (phi_index, i, imm));
 			break;
 		      }
 		  }
+		phi_index++;
 	      }
+	  }
 
+	/* Remove all edges for the current basic block.  */
+	for (int i = EDGE_COUNT (bb->succs) - 1; i >= 0; i--)
+ 	  {
+	    edge e = EDGE_SUCC (bb, i);
 	    remove_edge (e);
 	  }
 
@@ -4496,7 +4570,8 @@ convert_switch_statements ()
 
 	    basic_block label_bb = label_to_block_fn
 	      (func, CASE_LABEL (label));
-	    make_edge (cur_bb, label_bb, EDGE_TRUE_VALUE);
+	    edge new_edge = make_edge (cur_bb, label_bb, EDGE_TRUE_VALUE);
+	    new_edges.safe_push (new_edge);
 
 	    if (i < labels - 1)
 	      {
@@ -4514,36 +4589,27 @@ convert_switch_statements ()
 	      }
 	    else /* Link last IF statement and default label
 		    of the switch.  */
-	      make_edge (cur_bb, default_label_bb, EDGE_FALSE_VALUE);
+	      {
+		edge e = make_edge (cur_bb, default_label_bb, EDGE_FALSE_VALUE);
+		new_edges.safe_insert (0, e);
+	      }
 	  }
 
 	  /* Restore original PHI immediate value.  */
-	  for (unsigned i = 1; i < labels; i++)
+	  for (unsigned i = 0; i < phi_todo_list.length (); i++)
 	    {
-	      tree label = gimple_switch_label (s, i);
-	      basic_block label_bb = label_to_block_fn
-		(func, CASE_LABEL (label));
-	      gphi_iterator phi_gsi = gsi_start_phis (label_bb);
+	      phi_definition *phi_def = phi_todo_list[i];
+	      edge new_edge = new_edges[phi_def->label_index];
 
-	      if (!gsi_end_p (phi_gsi))
-		{
-		  gphi *phi = phi_gsi.phi ();
-
-		  for (unsigned j = 0; j < gimple_phi_num_args (phi); j++)
-		    {
-		      tree *slot = gimple_phi_arg_def_ptr (phi, j);
-		      if (!(*slot))
-			{
-			  basic_block dest = gimple_phi_arg_edge (phi, i)->dest;
-			  tree *imm = phi_defs.get (dest);
-			  gcc_assert (imm);
-			  *slot = *imm;
-			}
-		    }
-		}
-	    }
+	      gphi_iterator it = gsi_start_phis (new_edge->dest);
+	      for (unsigned i = 0; i < phi_def->phi_index; i++)
+		gsi_next (&it);
 
+	      gphi *phi = it.phi ();
+	      add_phi_arg (phi, phi_def->phi_value, new_edge, UNKNOWN_LOCATION);
+	    }
 
+	/* Remove the original GIMPLE switch statement.  */
 	gsi_remove (&gsi, true);
       }
   }
@@ -4558,7 +4624,6 @@ convert_switch_statements ()
     }
 }
 
-
 /* Generate HSAIL representation of the current function and write into a
    special section of the output file.  If KERNEL is set, the function will be
    considered an HSA kernel callable from the host, otherwise it will be
-- 
2.5.1

>From b73698cc9f8673a6efdbcf3a13a01c148adf9d38 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Wed, 16 Sep 2015 22:49:46 +0200
Subject: [PATCH 03/12] HSA: fix an HSA predicate.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa.c (hsa_type_integer_p): Add missing type.
---
 gcc/hsa.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/hsa.c b/gcc/hsa.c
index 1dbdcb4..3cb5a5a 100644
--- a/gcc/hsa.c
+++ b/gcc/hsa.c
@@ -434,6 +434,7 @@ hsa_type_integer_p (BrigType16_t type)
 {
   switch (type & BRIG_TYPE_BASE_MASK)
     {
+    case BRIG_TYPE_U8:
     case BRIG_TYPE_U16:
     case BRIG_TYPE_U32:
     case BRIG_TYPE_U64:
-- 
2.5.1

>From df466a156f05a34c23a36537e2d8e2fa2af20320 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Fri, 18 Sep 2015 06:12:52 +0200
Subject: [PATCH 04/12] HSA: fix ICE in compilation of a vector test.

gcc/ChangeLog:

2015-09-24  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_hsa_addr): Handle in a separate
	case BIT_FIELD_REFs with a SSA_NAME as the first argument.
	(gen_hsa_insns_for_bitfield): New function.
	(gen_hsa_insns_for_bitfield_load): Use the function.
	(gen_hsa_insns_for_load): Fix coding style.
---
 gcc/hsa-gen.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 16 deletions(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 5226dd8..7de9e33 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -1673,7 +1673,6 @@ gen_hsa_addr (tree ref, hsa_bb *hbb, vec <hsa_op_reg_p> *ssa_map,
 
   switch (TREE_CODE (ref))
     {
-    case SSA_NAME:
     case ADDR_EXPR:
       gcc_unreachable ();
 
@@ -1733,6 +1732,7 @@ gen_hsa_addr (tree ref, hsa_bb *hbb, vec <hsa_op_reg_p> *ssa_map,
     case FUNCTION_DECL:
       sorry ("HSA does not support indirect calls");
       goto out;
+    case SSA_NAME:
     default:
       sorry ("Support for HSA does not implement memory access to %E", origref);
       goto out;
@@ -1898,26 +1898,21 @@ hsa_build_append_simple_mov (hsa_op_reg *dest, hsa_op_base *src, hsa_bb *hbb)
   hbb->append_insn (insn);
 }
 
-/* Generate HSAIL instructions loading a bit field into register DEST.  ADDR is
-   prepared memory address which is used to load the bit field.  To identify
-   a bit file,d BITPOS is offset to the loaded memory and BITSIZE is number
-   of bits of the bit field.  Add instructions to HBB.  */
+/* Generate HSAIL instructions loading a bit field into register DEST.
+   VALUE_REG is a register of a SSA name that is used in the bit field
+   reference.  To identify a bit field BITPOS is offset to the loaded memory
+   and BITSIZE is number of bits of the bit field.
+   Add instructions to HBB.  */
 
-void
-gen_hsa_insns_for_bitfield_load (hsa_op_reg *dest, hsa_op_address *addr,
-				HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
-				hsa_bb *hbb)
+static void
+gen_hsa_insns_for_bitfield (hsa_op_reg *dest, hsa_op_reg *value_reg,
+			    HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
+			    hsa_bb *hbb)
 {
   unsigned type_bitsize = hsa_type_bit_size (dest->type);
   unsigned left_shift = type_bitsize - (bitsize + bitpos);
   unsigned right_shift = left_shift + bitpos;
 
-  hsa_op_reg *value_reg = new hsa_op_reg (dest->type);
-
-  hsa_insn_mem *mem = new hsa_insn_mem (BRIG_OPCODE_LD, dest->type, value_reg,
-					addr);
-  hbb->append_insn (mem);
-
   if (left_shift)
     {
       hsa_op_reg *value_reg_2 = new hsa_op_reg (dest->type);
@@ -1949,6 +1944,24 @@ gen_hsa_insns_for_bitfield_load (hsa_op_reg *dest, hsa_op_address *addr,
     hbb->append_insn (assignment);
 }
 
+
+/* Generate HSAIL instructions loading a bit field into register DEST.  ADDR is
+   prepared memory address which is used to load the bit field.  To identify
+   a bit field BITPOS is offset to the loaded memory and BITSIZE is number
+   of bits of the bit field.  Add instructions to HBB.  */
+
+static void
+gen_hsa_insns_for_bitfield_load (hsa_op_reg *dest, hsa_op_address *addr,
+				HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
+				hsa_bb *hbb)
+{
+  hsa_op_reg *value_reg = new hsa_op_reg (dest->type);
+  hsa_insn_mem *mem = new hsa_insn_mem (BRIG_OPCODE_LD, dest->type, value_reg,
+					addr);
+  hbb->append_insn (mem);
+  gen_hsa_insns_for_bitfield (dest, value_reg, bitsize, bitpos, hbb);
+}
+
 /* Generate HSAIL instructions loading something into register DEST.  RHS is
    tree representation of the loaded data, which are loaded as type TYPE.  Add
    instructions to HBB, use SSA_MAP for HSA SSA lookup.  */
@@ -2036,6 +2049,16 @@ gen_hsa_insns_for_load (hsa_op_reg *dest, tree rhs, tree type, hsa_bb *hbb,
 
       hbb->append_insn (insn);
     }
+  else if (TREE_CODE (rhs) == BIT_FIELD_REF
+	   && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+    {
+      tree ssa_name = TREE_OPERAND (rhs, 0);
+      HOST_WIDE_INT bitsize = tree_to_uhwi (TREE_OPERAND (rhs, 1));
+      HOST_WIDE_INT bitpos = tree_to_uhwi (TREE_OPERAND (rhs, 2));
+
+      hsa_op_reg *imm_value = hsa_reg_for_gimple_ssa (ssa_name, ssa_map);
+      gen_hsa_insns_for_bitfield (dest, imm_value, bitsize, bitpos, hbb);
+    }
   else if (DECL_P (rhs) || TREE_CODE (rhs) == MEM_REF
 	   || TREE_CODE (rhs) == TARGET_MEM_REF
 	   || handled_component_p (rhs))
@@ -2054,7 +2077,6 @@ gen_hsa_insns_for_load (hsa_op_reg *dest, tree rhs, tree type, hsa_bb *hbb,
 	  return;
 	}
 
-
       if (bitsize || bitpos)
 	gen_hsa_insns_for_bitfield_load (dest, addr, bitsize, bitpos, hbb);
       else
-- 
2.5.1

>From 1b2c8f01cfe545ef1586c7c7cc83fa992b5a90f9 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Fri, 18 Sep 2015 13:52:59 +0200
Subject: [PATCH 05/12] HSA: add support for empty ctors.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_hsa_ctor_assignment): New function.
	(gen_hsa_insns_for_single_assignment): Add support for
	CONSTRUCTOR.
---
 gcc/hsa-gen.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 7de9e33..03748c7 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -2329,6 +2329,23 @@ gen_hsa_memory_set (hsa_bb *hbb, hsa_op_address *target,
     }
 }
 
+/* Generate HSAIL instructions for a single assignment
+   of an empty constructor to an ADDR_LHS.  Constructor is passed as a
+   tree RHS and all instructions are appended to HBB.  */
+
+void
+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");
+      return;
+    }
+
+  unsigned size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (rhs)));
+  gen_hsa_memory_set (hbb, addr_lhs, 0, size);
+}
+
 /* Generate HSA instructions for a single assignment.  HBB is the basic block
    they will be appended to.  SSA_MAP maps gimple SSA names to HSA pseudo
    registers.  */
@@ -2360,10 +2377,16 @@ gen_hsa_insns_for_single_assignment (gimple *assign, hsa_bb *hbb,
   else
     {
       hsa_op_address *addr_lhs = gen_hsa_addr (lhs, hbb, ssa_map);
-      hsa_op_address *addr_rhs = gen_hsa_addr (rhs, hbb, ssa_map);
 
-      unsigned size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (rhs)));
-      gen_hsa_memory_copy (hbb, addr_lhs, addr_rhs, size);
+      if (TREE_CODE (rhs) == CONSTRUCTOR)
+	gen_hsa_ctor_assignment (addr_lhs, rhs, hbb);
+      else
+	{
+	  hsa_op_address *addr_rhs = gen_hsa_addr (rhs, hbb, ssa_map);
+
+	  unsigned size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (rhs)));
+	  gen_hsa_memory_copy (hbb, addr_lhs, addr_rhs, size);
+	}
     }
 }
 
-- 
2.5.1

>From 670275439f650d46c49a9a486830b48a33b45cb0 Mon Sep 17 00:00:00 2001
From: marxin <mli...@suse.cz>
Date: Tue, 22 Sep 2015 15:21:44 +0200
Subject: [PATCH 06/12] HSA: fix mem{cpy,set}

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_hsa_insns_for_single_assignment): Change
	arguments from a gimple assign to LHS and RHS. Emit insns
	for return values of memcpy and memset functions.
	(gen_hsa_insns_for_gimple_stmt): Use the newly added function.
---
 gcc/hsa-gen.c | 61 +++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 14 deletions(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 03748c7..ff4c904 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -2346,20 +2346,15 @@ gen_hsa_ctor_assignment (hsa_op_address *addr_lhs, tree rhs, hsa_bb *hbb)
   gen_hsa_memory_set (hbb, addr_lhs, 0, size);
 }
 
-/* Generate HSA instructions for a single assignment.  HBB is the basic block
-   they will be appended to.  SSA_MAP maps gimple SSA names to HSA pseudo
-   registers.  */
+/* Generate HSA instructions for a single assignment of RHS to LHS.
+   HBB is the basic block they will be appended to.  SSA_MAP maps gimple
+   SSA names to HSA pseudo registers.  */
 
 static void
-gen_hsa_insns_for_single_assignment (gimple *assign, hsa_bb *hbb,
+gen_hsa_insns_for_single_assignment (tree lhs, tree rhs, hsa_bb *hbb,
 				     vec <hsa_op_reg_p> *ssa_map)
 {
-  tree lhs = gimple_assign_lhs (assign);
-  tree rhs = gimple_assign_rhs1 (assign);
-
-  if (gimple_clobber_p (assign))
-    ;
-  else if (TREE_CODE (lhs) == SSA_NAME)
+  if (TREE_CODE (lhs) == SSA_NAME)
     {
       hsa_op_reg *dest = hsa_reg_for_gimple_ssa (lhs, ssa_map);
       gen_hsa_insns_for_load (dest, rhs, TREE_TYPE (lhs), hbb, ssa_map);
@@ -3698,6 +3693,8 @@ gen_hsa_ternary_atomic_for_builtin (bool ret_orig,
     }
 }
 
+#define HSA_MEMORY_BUILTINS_LIMIT     128
+
 /* Generate HSA instructions for the given call statement STMT.  Instructions
    will be appended to HBB.  SSA_MAP maps gimple SSA names to HSA pseudo
    registers.  */
@@ -4016,19 +4013,34 @@ specialop:
 	    return;
 	  }
 
+	unsigned n = tree_to_uhwi (byte_size);
+
+	/* 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);
+	    return;
+	  }
+
 	tree dst = gimple_call_arg (stmt, 0);
 	tree src = gimple_call_arg (stmt, 1);
 
 	hsa_op_address *dst_addr = get_address_from_value (dst, hbb, ssa_map);
 	hsa_op_address *src_addr = get_address_from_value (src, hbb, ssa_map);
-	unsigned n = tree_to_uhwi (byte_size);
 
 	gen_hsa_memory_copy (hbb, dst_addr, src_addr, n);
 
+	tree lhs = gimple_call_lhs (stmt);
+	if (lhs)
+	  gen_hsa_insns_for_single_assignment (lhs, dst, hbb, ssa_map);
+
 	break;
       }
     case BUILT_IN_MEMSET:
       {
+	tree dst = gimple_call_arg (stmt, 0);
 	tree c = gimple_call_arg (stmt, 1);
 
 	if (TREE_CODE (c) != INTEGER_CST)
@@ -4047,15 +4059,29 @@ specialop:
 	    return;
 	  }
 
+	unsigned n = tree_to_uhwi (byte_size);
+
+	/* 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);
+	    return;
+	  }
+
 	hsa_op_address *dst_addr;
-	dst_addr = get_address_from_value (gimple_call_arg (stmt, 0), hbb,
+	dst_addr = get_address_from_value (dst, hbb,
 					   ssa_map);
-	unsigned n = tree_to_uhwi (byte_size);
 	unsigned HOST_WIDE_INT constant = tree_to_uhwi
 	  (fold_convert (unsigned_char_type_node, c));
 
 	gen_hsa_memory_set (hbb, dst_addr, constant, n);
 
+	tree lhs = gimple_call_lhs (stmt);
+	if (lhs)
+	  gen_hsa_insns_for_single_assignment (lhs, dst, hbb, ssa_map);
+
 	break;
       }
     default:
@@ -4075,8 +4101,15 @@ gen_hsa_insns_for_gimple_stmt (gimple *stmt, hsa_bb *hbb,
   switch (gimple_code (stmt))
     {
     case GIMPLE_ASSIGN:
+      if (gimple_clobber_p (stmt))
+	break;
+
       if (gimple_assign_single_p (stmt))
-	gen_hsa_insns_for_single_assignment (stmt, hbb, ssa_map);
+	{
+	  tree lhs = gimple_assign_lhs (stmt);
+	  tree rhs = gimple_assign_rhs1 (stmt);
+	  gen_hsa_insns_for_single_assignment (lhs, rhs, hbb, ssa_map);
+	}
       else
 	gen_hsa_insns_for_operation_assignment (stmt, hbb, ssa_map);
       break;
-- 
2.5.1

>From 0bf687ec8b46c1b12237e924c5b676c8780a0b85 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Mon, 21 Sep 2015 14:54:16 +0200
Subject: [PATCH 07/12] HSA: fix rotate expansion with a constant first
 argument.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_hsa_insns_for_operation_assignment): Consider
	also an immediate value.
---
 gcc/hsa-gen.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index ff4c904..26112fd 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -2656,7 +2656,8 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb,
 	BrigType16_t btype = hsa_type_for_scalar_tree_type (TREE_TYPE (lhs),
 							    true);
 
-	hsa_op_reg *src = hsa_reg_for_gimple_ssa (rhs1, ssa_map);
+	hsa_op_with_type *src = hsa_reg_or_immed_for_gimple_op (rhs1, hbb,
+								ssa_map);
 	hsa_op_reg *op1 = new hsa_op_reg (btype);
 	hsa_op_reg *op2 = new hsa_op_reg (btype);
 	hsa_op_with_type *shift1 = hsa_reg_or_immed_for_gimple_op
-- 
2.5.1

>From 8c7999d8d6707bcc25863a30908a3157a12a9435 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Mon, 21 Sep 2015 15:56:16 +0200
Subject: [PATCH 08/12] HSA: fix emission of atomic insns.

gcc/ChangeLog:

2015-09-24  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_hsa_ternary_atomic_for_builtin): Fix memory types
	for certain memory insns. Fix memory order for ATOMIC_ST insns.
	(gen_hsa_insns_for_call): Emit a temporary HSA reg for ATOMIC_ST
	with no LHS.
---
 gcc/hsa-gen.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 26112fd..8c55c82 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -3619,7 +3619,18 @@ gen_hsa_ternary_atomic_for_builtin (bool ret_orig,
 
   tree type = TREE_TYPE (gimple_call_arg (stmt, 1));
   BrigType16_t hsa_type  = hsa_type_for_scalar_tree_type (type, false);
-  BrigType16_t mtype  = mem_type_for_type (hsa_type);
+  BrigType16_t mtype = mem_type_for_type (hsa_type);
+
+  /* Certain atomic insns must have Bx memory types.  */
+  switch (acode)
+    {
+    case BRIG_ATOMIC_LD:
+    case BRIG_ATOMIC_ST:
+      mtype = hsa_bittype_for_type (mtype);
+      break;
+    default:
+      break;
+    }
 
   hsa_op_reg *dest;
   int nops, opcode;
@@ -3640,6 +3651,12 @@ gen_hsa_ternary_atomic_for_builtin (bool ret_orig,
     }
 
   hsa_insn_atomic *atominsn = new hsa_insn_atomic (nops, opcode, acode, mtype);
+
+  /* Overwrite default memory order for ATOMIC_ST insn which can have just
+     RLX or SCREL memory order.  */
+  if (acode == BRIG_ATOMIC_ST)
+    atominsn->memoryorder = BRIG_MEMORY_ORDER_SC_RELEASE;
+
   hsa_op_address *addr;
   addr = get_address_from_value (gimple_call_arg (stmt, 0), hbb, ssa_map);
   /* TODO: Warn if addr has private segment, because the finalizer will not
@@ -3689,7 +3706,7 @@ gen_hsa_ternary_atomic_for_builtin (bool ret_orig,
 	default:
 	  gcc_unreachable ();
 	}
-      hsa_op_reg *real_dest = dest = hsa_reg_for_gimple_ssa (lhs, ssa_map);
+      hsa_op_reg *real_dest = hsa_reg_for_gimple_ssa (lhs, ssa_map);
       gen_hsa_binary_operation (arith, real_dest, dest, op, hbb);
     }
 }
@@ -3826,11 +3843,23 @@ specialop:
     case BUILT_IN_ATOMIC_LOAD_8:
     case BUILT_IN_ATOMIC_LOAD_16:
       {
-	BrigType16_t mtype = mem_type_for_type (hsa_type_for_scalar_tree_type
-						(TREE_TYPE (lhs), false));
+	BrigType16_t mtype;
 	hsa_op_address *addr;
 	addr = get_address_from_value (gimple_call_arg (stmt, 0), hbb, ssa_map);
-	dest = hsa_reg_for_gimple_ssa (lhs, ssa_map);
+
+	if (lhs)
+	  {
+	    mtype = mem_type_for_type
+	      (hsa_type_for_scalar_tree_type (TREE_TYPE (lhs), false));
+	    mtype = hsa_bittype_for_type (mtype);
+	    dest = hsa_reg_for_gimple_ssa (lhs, ssa_map);
+	  }
+	else
+	  {
+	    mtype = BRIG_TYPE_B64;
+	    dest = new hsa_op_reg (mtype);
+	  }
+
 	hsa_insn_atomic *atominsn
 	  = new hsa_insn_atomic (2, BRIG_OPCODE_ATOMIC, BRIG_ATOMIC_LD, mtype,
 				 dest, addr);
-- 
2.5.1

>From 7c7c57a55f456d2a6d364b7e86a6b86f3d9cd936 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Mon, 21 Sep 2015 16:43:57 +0200
Subject: [PATCH 09/12] HSA: sorry in case of complex recursive edges presented
 in CFG.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_body_from_gimple): Verify edges in CFG.
---
 gcc/hsa-gen.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 8c55c82..2ad7f25 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -4309,6 +4309,24 @@ gen_body_from_gimple (vec <hsa_op_reg_p> *ssa_map)
 {
   basic_block bb;
 
+  /* Verify CFG for complex edges we are unable to handle.  */
+  edge_iterator ei;
+  edge e;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      FOR_EACH_EDGE (e, ei, bb->succs)
+	{
+	  /* Verify all unsupported flags for edges that point
+	     to the same basic block.  */
+	  if (e->flags & EDGE_EH)
+	    {
+	      sorry ("Support for HSA does not implement exception handling");
+	      return;
+	    }
+	}
+    }
+
   FOR_EACH_BB_FN (bb, cfun)
     {
       gimple_stmt_iterator gsi;
-- 
2.5.1

>From b79576f42c471dcf5e5574f3e4e206cb79810e6f Mon Sep 17 00:00:00 2001
From: marxin <mli...@suse.cz>
Date: Tue, 22 Sep 2015 16:33:06 +0200
Subject: [PATCH 10/12] HSA: add seen_error guard to assignment emission.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-gen.c (gen_hsa_insns_for_single_assignment): Add
	seen_error guard.
---
 gcc/hsa-gen.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 2ad7f25..819374a 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -2357,6 +2357,9 @@ 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 ())
+	return;
+
       gen_hsa_insns_for_load (dest, rhs, TREE_TYPE (lhs), hbb, ssa_map);
     }
   else if (TREE_CODE (rhs) == SSA_NAME
-- 
2.5.1

>From 7808c7e0fc9e403ee8df0b0f66e481f66669e4ab Mon Sep 17 00:00:00 2001
From: marxin <mli...@suse.cz>
Date: Wed, 23 Sep 2015 12:59:33 +0200
Subject: [PATCH 11/12] HSA: handle CTORs and verify function arguments.

gcc/ChangeLog:

2015-09-23  Martin Liska  <mli...@suse.cz>

	* hsa-brig.c (hsa_op_immed::emit_to_buffer): Fix handling
	of CTORs.
	* hsa-gen.c (hsa_op_immed::hsa_op_immed): Add new CTOR
	verification.
	(verify_function_arguments): New function.
	(gen_hsa_insns_for_direct_call): Use the function.
	(generate_hsa): Use the newly added function.
	* hsa.h: Declare a new function.
---
 gcc/hsa-brig.c |  6 ++++--
 gcc/hsa-gen.c  | 55 ++++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/gcc/hsa-brig.c b/gcc/hsa-brig.c
index 510496d..36911be 100644
--- a/gcc/hsa-brig.c
+++ b/gcc/hsa-brig.c
@@ -914,7 +914,10 @@ void
 hsa_op_immed::emit_to_buffer (tree value)
 {
   unsigned total_len = brig_repr_size;
-  brig_repr = XNEWVEC (char, total_len);
+
+  /* As we can have a constructor with fewer elements, fill the memory
+     with zeros.  */
+  brig_repr = XCNEWVEC (char, total_len);
   char *p = brig_repr;
 
   if (TREE_CODE (value) == VECTOR_CST)
@@ -957,7 +960,6 @@ hsa_op_immed::emit_to_buffer (tree value)
 	  total_len -= actual;
 	  p += actual;
 	}
-      gcc_assert (total_len == 0);
     }
   else
     emit_immediate_scalar_to_buffer (value, p, total_len);
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 819374a..966989c 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -767,18 +767,34 @@ 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 ())
+    return;
+
   gcc_checking_assert ((is_gimple_min_invariant (tree_val)
 		       && (!POINTER_TYPE_P (TREE_TYPE (tree_val))
 			   || TREE_CODE (tree_val) == INTEGER_CST))
 		       || TREE_CODE (tree_val) == CONSTRUCTOR);
   tree_value = tree_val;
-
   brig_repr_size = hsa_get_imm_brig_type_len (type);
 
   if (TREE_CODE (tree_value) == STRING_CST)
     brig_repr_size = TREE_STRING_LENGTH (tree_value);
   else if (TREE_CODE (tree_value) == CONSTRUCTOR)
-    brig_repr_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (tree_value)));
+    {
+      brig_repr_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (tree_value)));
+
+      /* Verify that all elements of a contructor are constants.  */
+      for (unsigned i = 0; i < vec_safe_length (CONSTRUCTOR_ELTS (tree_value));
+	   i++)
+	{
+	  tree v = CONSTRUCTOR_ELT (tree_value, i)->value;
+	  if (!CONSTANT_CLASS_P (v))
+	    {
+	      sorry ("HSA ctor should have only constants");
+	      return;
+	    }
+	}
+    }
 
   emit_to_buffer (tree_value);
   hsa_list_operand_immed.safe_push (this);
@@ -2977,6 +2993,23 @@ gen_hsa_insns_for_switch_stmt (gswitch *s, hsa_bb *hbb,
   hbb->append_insn (sbr);
 }
 
+/* Verify that the function DECL can be handled by HSA.  */
+
+static void
+verify_function_arguments (tree decl)
+{
+  if (DECL_STATIC_CHAIN (decl))
+    {
+      sorry ("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);
+      return;
+    }
+}
 
 /* Generate HSA instructions for a direct call instruction.
    Instructions will be appended to HBB, which also needs to be the
@@ -2988,6 +3021,10 @@ gen_hsa_insns_for_direct_call (gimple *stmt, hsa_bb *hbb,
 			       vec <hsa_op_reg_p> *ssa_map)
 {
   tree decl = gimple_call_fndecl (stmt);
+  verify_function_arguments (decl);
+  if (seen_error ())
+    return;
+
   hsa_insn_call *call_insn = new hsa_insn_call (decl);
   hsa_cfun->called_functions.safe_push (call_insn->called_function);
 
@@ -4761,17 +4798,9 @@ convert_switch_statements ()
 static void
 generate_hsa (bool kernel)
 {
-  if (DECL_STATIC_CHAIN (cfun->decl))
-    {
-      sorry ("HSA does not support nested functions");
-      return;
-    }
-  else if (!TYPE_ARG_TYPES (TREE_TYPE (cfun->decl)))
-    {
-      sorry ("HSA does not support functions with variadic arguments "
-	     "(or unknown return type)");
-      return;
-    }
+  verify_function_arguments (cfun->decl);
+  if (seen_error ())
+    return;
 
   vec <hsa_op_reg_p> ssa_map = vNULL;
 
-- 
2.5.1

Reply via email to