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