From: Martin Jambor Date: Fri, 20 Jan 2017 13:33:29 +0000 (+0100) Subject: [hsa] Rename hsa.[ch] to hsa-common.[ch] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=13293add082aa485e64228b5fd6dfbacc1d47929;p=gcc.git [hsa] Rename hsa.[ch] to hsa-common.[ch] 2017-01-20 Martin Jambor * hsa.h: Renaed to hsa-common.h. Adjusted a comment. * hsa.c: Renaed to hsa-common.c. Change include of gt-hsa.h to gt-hsa-common.h. * Makefile.in (OBJS): Rename hsa.o to hsa-common.o. (GTFILES): Rename hsa.c to hsa-common.c. * hsa-brig.c: Change include of hsa.h to hsa-common.h. * hsa-dump.c: Likewise. * hsa-gen.c: Likewise. * hsa-regalloc.c: Likewise. * ipa-hsa.c: Likewise. * omp-expand.c: Likewise. * omp-low.c: Likewise. * toplev.c: Likewise. From-SVN: r244711 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 38eeb5a21b9..a27331249b8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2017-01-20 Martin Jambor + + * hsa.h: Renaed to hsa-common.h. Adjusted a comment. + * hsa.c: Renaed to hsa-common.c. Change include of gt-hsa.h to + gt-hsa-common.h. + * Makefile.in (OBJS): Rename hsa.o to hsa-common.o. + (GTFILES): Rename hsa.c to hsa-common.c. + * hsa-brig.c: Change include of hsa.h to hsa-common.h. + * hsa-dump.c: Likewise. + * hsa-gen.c: Likewise. + * hsa-regalloc.c: Likewise. + * ipa-hsa.c: Likewise. + * omp-expand.c: Likewise. + * omp-low.c: Likewise. + * toplev.c: Likewise. + 2017-01-20 Marek Polacek PR c/64279 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 7a7e27ac295..df02246e31e 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1320,7 +1320,7 @@ OBJS = \ haifa-sched.o \ hash-map-tests.o \ hash-set-tests.o \ - hsa.o \ + hsa-common.o \ hsa-gen.o \ hsa-regalloc.o \ hsa-brig.o \ @@ -2508,7 +2508,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/sancov.c \ $(srcdir)/ipa-devirt.c \ $(srcdir)/internal-fn.h \ - $(srcdir)/hsa.c \ + $(srcdir)/hsa-common.c \ @all_gtfiles@ # Compute the list of GT header files from the corresponding C sources, diff --git a/gcc/hsa-brig.c b/gcc/hsa-brig.c index 5fe302f25f5..1a2d45fcc52 100644 --- a/gcc/hsa-brig.c +++ b/gcc/hsa-brig.c @@ -44,7 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "print-tree.h" #include "symbol-summary.h" -#include "hsa.h" +#include "hsa-common.h" #include "gomp-constants.h" /* Convert VAL to little endian form, if necessary. */ diff --git a/gcc/hsa-common.c b/gcc/hsa-common.c new file mode 100644 index 00000000000..95636ebc9a8 --- /dev/null +++ b/gcc/hsa-common.c @@ -0,0 +1,994 @@ +/* Implementation of commonly needed HSAIL related functions and methods. + Copyright (C) 2013-2017 Free Software Foundation, Inc. + Contributed by Martin Jambor and + Martin Liska . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "is-a.h" +#include "hash-set.h" +#include "hash-map.h" +#include "vec.h" +#include "tree.h" +#include "dumpfile.h" +#include "gimple-pretty-print.h" +#include "diagnostic-core.h" +#include "alloc-pool.h" +#include "cgraph.h" +#include "print-tree.h" +#include "stringpool.h" +#include "symbol-summary.h" +#include "hsa-common.h" +#include "internal-fn.h" +#include "ctype.h" +#include "builtins.h" + +/* Structure containing intermediate HSA representation of the generated + function. */ +class hsa_function_representation *hsa_cfun; + +/* Element of the mapping vector between a host decl and an HSA kernel. */ + +struct GTY(()) hsa_decl_kernel_map_element +{ + /* The decl of the host function. */ + tree decl; + /* Name of the HSA kernel in BRIG. */ + char * GTY((skip)) name; + /* Size of OMP data, if the kernel contains a kernel dispatch. */ + unsigned omp_data_size; + /* True if the function is gridified kernel. */ + bool gridified_kernel_p; +}; + +/* Mapping between decls and corresponding HSA kernels in this compilation + unit. */ + +static GTY (()) vec + *hsa_decl_kernel_mapping; + +/* Mapping between decls and corresponding HSA kernels + called by the function. */ +hash_map *> *hsa_decl_kernel_dependencies; + +/* Hash function to lookup a symbol for a decl. */ +hash_table *hsa_global_variable_symbols; + +/* HSA summaries. */ +hsa_summary_t *hsa_summaries = NULL; + +/* HSA number of threads. */ +hsa_symbol *hsa_num_threads = NULL; + +/* HSA function that cannot be expanded to HSAIL. */ +hash_set *hsa_failed_functions = NULL; + +/* True if compilation unit-wide data are already allocated and initialized. */ +static bool compilation_unit_data_initialized; + +/* Return true if FNDECL represents an HSA-callable function. */ + +bool +hsa_callable_function_p (tree fndecl) +{ + return (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl)) + && !lookup_attribute ("oacc function", DECL_ATTRIBUTES (fndecl))); +} + +/* Allocate HSA structures that are are used when dealing with different + functions. */ + +void +hsa_init_compilation_unit_data (void) +{ + if (compilation_unit_data_initialized) + return; + + compilation_unit_data_initialized = true; + + hsa_global_variable_symbols = new hash_table (8); + hsa_failed_functions = new hash_set (); + hsa_emitted_internal_decls = new hash_table (2); +} + +/* Free data structures that are used when dealing with different + functions. */ + +void +hsa_deinit_compilation_unit_data (void) +{ + gcc_assert (compilation_unit_data_initialized); + + delete hsa_failed_functions; + delete hsa_emitted_internal_decls; + + for (hash_table ::iterator it + = hsa_global_variable_symbols->begin (); + it != hsa_global_variable_symbols->end (); + ++it) + { + hsa_symbol *sym = *it; + delete sym; + } + + delete hsa_global_variable_symbols; + + if (hsa_num_threads) + { + delete hsa_num_threads; + hsa_num_threads = NULL; + } + + compilation_unit_data_initialized = false; +} + +/* Return true if we are generating large HSA machine model. */ + +bool +hsa_machine_large_p (void) +{ + /* FIXME: I suppose this is technically wrong but should work for me now. */ + return (GET_MODE_BITSIZE (Pmode) == 64); +} + +/* Return the HSA profile we are using. */ + +bool +hsa_full_profile_p (void) +{ + return true; +} + +/* Return true if a register in operand number OPNUM of instruction + is an output. False if it is an input. */ + +bool +hsa_insn_basic::op_output_p (unsigned opnum) +{ + switch (m_opcode) + { + case HSA_OPCODE_PHI: + case BRIG_OPCODE_CBR: + case BRIG_OPCODE_SBR: + case BRIG_OPCODE_ST: + case BRIG_OPCODE_SIGNALNORET: + case BRIG_OPCODE_DEBUGTRAP: + /* FIXME: There are probably missing cases here, double check. */ + return false; + case BRIG_OPCODE_EXPAND: + /* Example: expand_v4_b32_b128 (dest0, dest1, dest2, dest3), src0. */ + return opnum < operand_count () - 1; + default: + return opnum == 0; + } +} + +/* Return true if OPCODE is an floating-point bit instruction opcode. */ + +bool +hsa_opcode_floating_bit_insn_p (BrigOpcode16_t opcode) +{ + switch (opcode) + { + case BRIG_OPCODE_NEG: + case BRIG_OPCODE_ABS: + case BRIG_OPCODE_CLASS: + case BRIG_OPCODE_COPYSIGN: + return true; + default: + return false; + } +} + +/* Return the number of destination operands for this INSN. */ + +unsigned +hsa_insn_basic::input_count () +{ + switch (m_opcode) + { + default: + return 1; + + case BRIG_OPCODE_NOP: + return 0; + + case BRIG_OPCODE_EXPAND: + return 2; + + case BRIG_OPCODE_LD: + /* ld_v[234] not yet handled. */ + return 1; + + case BRIG_OPCODE_ST: + return 0; + + case BRIG_OPCODE_ATOMICNORET: + return 0; + + case BRIG_OPCODE_SIGNAL: + return 1; + + case BRIG_OPCODE_SIGNALNORET: + return 0; + + case BRIG_OPCODE_MEMFENCE: + return 0; + + case BRIG_OPCODE_RDIMAGE: + case BRIG_OPCODE_LDIMAGE: + case BRIG_OPCODE_STIMAGE: + case BRIG_OPCODE_QUERYIMAGE: + case BRIG_OPCODE_QUERYSAMPLER: + sorry ("HSA image ops not handled"); + return 0; + + case BRIG_OPCODE_CBR: + case BRIG_OPCODE_BR: + return 0; + + case BRIG_OPCODE_SBR: + return 0; /* ??? */ + + case BRIG_OPCODE_WAVEBARRIER: + return 0; /* ??? */ + + case BRIG_OPCODE_BARRIER: + case BRIG_OPCODE_ARRIVEFBAR: + case BRIG_OPCODE_INITFBAR: + case BRIG_OPCODE_JOINFBAR: + case BRIG_OPCODE_LEAVEFBAR: + case BRIG_OPCODE_RELEASEFBAR: + case BRIG_OPCODE_WAITFBAR: + return 0; + + case BRIG_OPCODE_LDF: + return 1; + + case BRIG_OPCODE_ACTIVELANECOUNT: + case BRIG_OPCODE_ACTIVELANEID: + case BRIG_OPCODE_ACTIVELANEMASK: + case BRIG_OPCODE_ACTIVELANEPERMUTE: + return 1; /* ??? */ + + case BRIG_OPCODE_CALL: + case BRIG_OPCODE_SCALL: + case BRIG_OPCODE_ICALL: + return 0; + + case BRIG_OPCODE_RET: + return 0; + + case BRIG_OPCODE_ALLOCA: + return 1; + + case BRIG_OPCODE_CLEARDETECTEXCEPT: + return 0; + + case BRIG_OPCODE_SETDETECTEXCEPT: + return 0; + + case BRIG_OPCODE_PACKETCOMPLETIONSIG: + case BRIG_OPCODE_PACKETID: + case BRIG_OPCODE_CASQUEUEWRITEINDEX: + case BRIG_OPCODE_LDQUEUEREADINDEX: + case BRIG_OPCODE_LDQUEUEWRITEINDEX: + case BRIG_OPCODE_STQUEUEREADINDEX: + case BRIG_OPCODE_STQUEUEWRITEINDEX: + return 1; /* ??? */ + + case BRIG_OPCODE_ADDQUEUEWRITEINDEX: + return 1; + + case BRIG_OPCODE_DEBUGTRAP: + return 0; + + case BRIG_OPCODE_GROUPBASEPTR: + case BRIG_OPCODE_KERNARGBASEPTR: + return 1; /* ??? */ + + case HSA_OPCODE_ARG_BLOCK: + return 0; + + case BRIG_KIND_DIRECTIVE_COMMENT: + return 0; + } +} + +/* Return the number of source operands for this INSN. */ + +unsigned +hsa_insn_basic::num_used_ops () +{ + gcc_checking_assert (input_count () <= operand_count ()); + + return operand_count () - input_count (); +} + +/* Set alignment to VALUE. */ + +void +hsa_insn_mem::set_align (BrigAlignment8_t value) +{ + /* TODO: Perhaps remove this dump later on: */ + if (dump_file && (dump_flags & TDF_DETAILS) && value < m_align) + { + fprintf (dump_file, "Decreasing alignment to %u in instruction ", value); + dump_hsa_insn (dump_file, this); + } + m_align = value; +} + +/* Return size of HSA type T in bits. */ + +unsigned +hsa_type_bit_size (BrigType16_t t) +{ + switch (t) + { + case BRIG_TYPE_B1: + return 1; + + case BRIG_TYPE_U8: + case BRIG_TYPE_S8: + case BRIG_TYPE_B8: + return 8; + + case BRIG_TYPE_U16: + case BRIG_TYPE_S16: + case BRIG_TYPE_B16: + case BRIG_TYPE_F16: + return 16; + + case BRIG_TYPE_U32: + case BRIG_TYPE_S32: + case BRIG_TYPE_B32: + case BRIG_TYPE_F32: + case BRIG_TYPE_U8X4: + case BRIG_TYPE_U16X2: + case BRIG_TYPE_S8X4: + case BRIG_TYPE_S16X2: + case BRIG_TYPE_F16X2: + return 32; + + case BRIG_TYPE_U64: + case BRIG_TYPE_S64: + case BRIG_TYPE_F64: + case BRIG_TYPE_B64: + case BRIG_TYPE_U8X8: + case BRIG_TYPE_U16X4: + case BRIG_TYPE_U32X2: + case BRIG_TYPE_S8X8: + case BRIG_TYPE_S16X4: + case BRIG_TYPE_S32X2: + case BRIG_TYPE_F16X4: + case BRIG_TYPE_F32X2: + + return 64; + + case BRIG_TYPE_B128: + case BRIG_TYPE_U8X16: + case BRIG_TYPE_U16X8: + case BRIG_TYPE_U32X4: + case BRIG_TYPE_U64X2: + case BRIG_TYPE_S8X16: + case BRIG_TYPE_S16X8: + case BRIG_TYPE_S32X4: + case BRIG_TYPE_S64X2: + case BRIG_TYPE_F16X8: + case BRIG_TYPE_F32X4: + case BRIG_TYPE_F64X2: + return 128; + + default: + gcc_assert (hsa_seen_error ()); + return t; + } +} + +/* Return BRIG bit-type with BITSIZE length. */ + +BrigType16_t +hsa_bittype_for_bitsize (unsigned bitsize) +{ + switch (bitsize) + { + case 1: + return BRIG_TYPE_B1; + case 8: + return BRIG_TYPE_B8; + case 16: + return BRIG_TYPE_B16; + case 32: + return BRIG_TYPE_B32; + case 64: + return BRIG_TYPE_B64; + case 128: + return BRIG_TYPE_B128; + default: + gcc_unreachable (); + } +} + +/* Return BRIG unsigned int type with BITSIZE length. */ + +BrigType16_t +hsa_uint_for_bitsize (unsigned bitsize) +{ + switch (bitsize) + { + case 8: + return BRIG_TYPE_U8; + case 16: + return BRIG_TYPE_U16; + case 32: + return BRIG_TYPE_U32; + case 64: + return BRIG_TYPE_U64; + default: + gcc_unreachable (); + } +} + +/* Return BRIG float type with BITSIZE length. */ + +BrigType16_t +hsa_float_for_bitsize (unsigned bitsize) +{ + switch (bitsize) + { + case 16: + return BRIG_TYPE_F16; + case 32: + return BRIG_TYPE_F32; + case 64: + return BRIG_TYPE_F64; + default: + gcc_unreachable (); + } +} + +/* Return HSA bit-type with the same size as the type T. */ + +BrigType16_t +hsa_bittype_for_type (BrigType16_t t) +{ + return hsa_bittype_for_bitsize (hsa_type_bit_size (t)); +} + +/* Return HSA unsigned integer type with the same size as the type T. */ + +BrigType16_t +hsa_unsigned_type_for_type (BrigType16_t t) +{ + return hsa_uint_for_bitsize (hsa_type_bit_size (t)); +} + +/* Return true if TYPE is a packed HSA type. */ + +bool +hsa_type_packed_p (BrigType16_t type) +{ + return (type & BRIG_TYPE_PACK_MASK) != BRIG_TYPE_PACK_NONE; +} + +/* Return true if and only if TYPE is a floating point number type. */ + +bool +hsa_type_float_p (BrigType16_t type) +{ + switch (type & BRIG_TYPE_BASE_MASK) + { + case BRIG_TYPE_F16: + case BRIG_TYPE_F32: + case BRIG_TYPE_F64: + return true; + default: + return false; + } +} + +/* Return true if and only if TYPE is an integer number type. */ + +bool +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: + case BRIG_TYPE_S8: + case BRIG_TYPE_S16: + case BRIG_TYPE_S32: + case BRIG_TYPE_S64: + return true; + default: + return false; + } +} + +/* Return true if and only if TYPE is an bit-type. */ + +bool +hsa_btype_p (BrigType16_t type) +{ + switch (type & BRIG_TYPE_BASE_MASK) + { + case BRIG_TYPE_B8: + case BRIG_TYPE_B16: + case BRIG_TYPE_B32: + case BRIG_TYPE_B64: + case BRIG_TYPE_B128: + return true; + default: + return false; + } +} + + +/* Return HSA alignment encoding alignment to N bits. */ + +BrigAlignment8_t +hsa_alignment_encoding (unsigned n) +{ + gcc_assert (n >= 8 && !(n & (n - 1))); + if (n >= 256) + return BRIG_ALIGNMENT_32; + + switch (n) + { + case 8: + return BRIG_ALIGNMENT_1; + case 16: + return BRIG_ALIGNMENT_2; + case 32: + return BRIG_ALIGNMENT_4; + case 64: + return BRIG_ALIGNMENT_8; + case 128: + return BRIG_ALIGNMENT_16; + default: + gcc_unreachable (); + } +} + +/* Return HSA alignment encoding alignment of T got + by get_object_alignment. */ + +BrigAlignment8_t +hsa_object_alignment (tree t) +{ + return hsa_alignment_encoding (get_object_alignment (t)); +} + +/* Return byte alignment for given BrigAlignment8_t value. */ + +unsigned +hsa_byte_alignment (BrigAlignment8_t alignment) +{ + gcc_assert (alignment != BRIG_ALIGNMENT_NONE); + + return 1 << (alignment - 1); +} + +/* Return natural alignment of HSA TYPE. */ + +BrigAlignment8_t +hsa_natural_alignment (BrigType16_t type) +{ + return hsa_alignment_encoding (hsa_type_bit_size (type & ~BRIG_TYPE_ARRAY)); +} + +/* Call the correct destructor of a HSA instruction. */ + +void +hsa_destroy_insn (hsa_insn_basic *insn) +{ + if (hsa_insn_phi *phi = dyn_cast (insn)) + phi->~hsa_insn_phi (); + else if (hsa_insn_cbr *br = dyn_cast (insn)) + br->~hsa_insn_cbr (); + else if (hsa_insn_cmp *cmp = dyn_cast (insn)) + cmp->~hsa_insn_cmp (); + else if (hsa_insn_mem *mem = dyn_cast (insn)) + mem->~hsa_insn_mem (); + else if (hsa_insn_atomic *atomic = dyn_cast (insn)) + atomic->~hsa_insn_atomic (); + else if (hsa_insn_seg *seg = dyn_cast (insn)) + seg->~hsa_insn_seg (); + else if (hsa_insn_call *call = dyn_cast (insn)) + call->~hsa_insn_call (); + else if (hsa_insn_arg_block *block = dyn_cast (insn)) + block->~hsa_insn_arg_block (); + else if (hsa_insn_sbr *sbr = dyn_cast (insn)) + sbr->~hsa_insn_sbr (); + else if (hsa_insn_br *br = dyn_cast (insn)) + br->~hsa_insn_br (); + else if (hsa_insn_comment *comment = dyn_cast (insn)) + comment->~hsa_insn_comment (); + else + insn->~hsa_insn_basic (); +} + +/* Call the correct destructor of a HSA operand. */ + +void +hsa_destroy_operand (hsa_op_base *op) +{ + if (hsa_op_code_list *list = dyn_cast (op)) + list->~hsa_op_code_list (); + else if (hsa_op_operand_list *list = dyn_cast (op)) + list->~hsa_op_operand_list (); + else if (hsa_op_reg *reg = dyn_cast (op)) + reg->~hsa_op_reg (); + else if (hsa_op_immed *immed = dyn_cast (op)) + immed->~hsa_op_immed (); + else + op->~hsa_op_base (); +} + +/* Create a mapping between the original function DECL and kernel name NAME. */ + +void +hsa_add_kern_decl_mapping (tree decl, char *name, unsigned omp_data_size, + bool gridified_kernel_p) +{ + hsa_decl_kernel_map_element dkm; + dkm.decl = decl; + dkm.name = name; + dkm.omp_data_size = omp_data_size; + dkm.gridified_kernel_p = gridified_kernel_p; + vec_safe_push (hsa_decl_kernel_mapping, dkm); +} + +/* Return the number of kernel decl name mappings. */ + +unsigned +hsa_get_number_decl_kernel_mappings (void) +{ + return vec_safe_length (hsa_decl_kernel_mapping); +} + +/* Return the decl in the Ith kernel decl name mapping. */ + +tree +hsa_get_decl_kernel_mapping_decl (unsigned i) +{ + return (*hsa_decl_kernel_mapping)[i].decl; +} + +/* Return the name in the Ith kernel decl name mapping. */ + +char * +hsa_get_decl_kernel_mapping_name (unsigned i) +{ + return (*hsa_decl_kernel_mapping)[i].name; +} + +/* Return maximum OMP size for kernel decl name mapping. */ + +unsigned +hsa_get_decl_kernel_mapping_omp_size (unsigned i) +{ + return (*hsa_decl_kernel_mapping)[i].omp_data_size; +} + +/* Return if the function is gridified kernel in decl name mapping. */ + +bool +hsa_get_decl_kernel_mapping_gridified (unsigned i) +{ + return (*hsa_decl_kernel_mapping)[i].gridified_kernel_p; +} + +/* Free the mapping between original decls and kernel names. */ + +void +hsa_free_decl_kernel_mapping (void) +{ + if (hsa_decl_kernel_mapping == NULL) + return; + + for (unsigned i = 0; i < hsa_decl_kernel_mapping->length (); ++i) + free ((*hsa_decl_kernel_mapping)[i].name); + ggc_free (hsa_decl_kernel_mapping); +} + +/* Add new kernel dependency. */ + +void +hsa_add_kernel_dependency (tree caller, const char *called_function) +{ + if (hsa_decl_kernel_dependencies == NULL) + hsa_decl_kernel_dependencies = new hash_map *> (); + + vec *s = NULL; + vec **slot = hsa_decl_kernel_dependencies->get (caller); + if (slot == NULL) + { + s = new vec (); + hsa_decl_kernel_dependencies->put (caller, s); + } + else + s = *slot; + + s->safe_push (called_function); +} + +/* Expansion to HSA needs a few gc roots to hold types, constructors etc. In + order to minimize the number of GTY roots, we'll root them all in the + following array. The individual elements should only be accessed by the + very simple getters (of a pointer-to-tree) below. */ + +static GTY(()) tree hsa_tree_gt_roots[3]; + +tree * +hsa_get_ctor_statements (void) +{ + return &hsa_tree_gt_roots[0]; +} + +tree * +hsa_get_dtor_statements (void) +{ + return &hsa_tree_gt_roots[1]; +} + +tree * +hsa_get_kernel_dispatch_type (void) +{ + return &hsa_tree_gt_roots[2]; +} + +/* Modify the name P in-place so that it is a valid HSA identifier. */ + +void +hsa_sanitize_name (char *p) +{ + for (; *p; p++) + if (*p == '.' || *p == '-') + *p = '_'; +} + +/* Clone the name P, set trailing ampersand and sanitize the name. */ + +char * +hsa_brig_function_name (const char *p) +{ + unsigned len = strlen (p); + char *buf = XNEWVEC (char, len + 2); + + buf[0] = '&'; + buf[len + 1] = '\0'; + memcpy (buf + 1, p, len); + + hsa_sanitize_name (buf); + return buf; +} + +/* Add a flatten attribute and disable vectorization for gpu implementation + function decl GDECL. */ + +void hsa_summary_t::process_gpu_implementation_attributes (tree gdecl) +{ + DECL_ATTRIBUTES (gdecl) + = tree_cons (get_identifier ("flatten"), NULL_TREE, + DECL_ATTRIBUTES (gdecl)); + + tree fn_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (gdecl); + if (fn_opts == NULL_TREE) + fn_opts = optimization_default_node; + fn_opts = copy_node (fn_opts); + TREE_OPTIMIZATION (fn_opts)->x_flag_tree_loop_vectorize = false; + TREE_OPTIMIZATION (fn_opts)->x_flag_tree_slp_vectorize = false; + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (gdecl) = fn_opts; +} + +void +hsa_summary_t::link_functions (cgraph_node *gpu, cgraph_node *host, + hsa_function_kind kind, bool gridified_kernel_p) +{ + hsa_function_summary *gpu_summary = get (gpu); + hsa_function_summary *host_summary = get (host); + + gpu_summary->m_kind = kind; + host_summary->m_kind = kind; + + gpu_summary->m_gpu_implementation_p = true; + host_summary->m_gpu_implementation_p = false; + + gpu_summary->m_gridified_kernel_p = gridified_kernel_p; + host_summary->m_gridified_kernel_p = gridified_kernel_p; + + gpu_summary->m_bound_function = host; + host_summary->m_bound_function = gpu; + + process_gpu_implementation_attributes (gpu->decl); + + /* Create reference between a kernel and a corresponding host implementation + to quarantee LTO streaming to a same LTRANS. */ + if (kind == HSA_KERNEL) + gpu->create_reference (host, IPA_REF_ADDR); +} + +/* Add a HOST function to HSA summaries. */ + +void +hsa_register_kernel (cgraph_node *host) +{ + if (hsa_summaries == NULL) + hsa_summaries = new hsa_summary_t (symtab); + hsa_function_summary *s = hsa_summaries->get (host); + s->m_kind = HSA_KERNEL; +} + +/* Add a pair of functions to HSA summaries. GPU is an HSA implementation of + a HOST function. */ + +void +hsa_register_kernel (cgraph_node *gpu, cgraph_node *host) +{ + if (hsa_summaries == NULL) + hsa_summaries = new hsa_summary_t (symtab); + hsa_summaries->link_functions (gpu, host, HSA_KERNEL, true); +} + +/* Return true if expansion of the current HSA function has already failed. */ + +bool +hsa_seen_error (void) +{ + return hsa_cfun->m_seen_error; +} + +/* Mark current HSA function as failed. */ + +void +hsa_fail_cfun (void) +{ + hsa_failed_functions->add (hsa_cfun->m_decl); + hsa_cfun->m_seen_error = true; +} + +char * +hsa_internal_fn::name () +{ + char *name = xstrdup (internal_fn_name (m_fn)); + for (char *ptr = name; *ptr; ptr++) + *ptr = TOLOWER (*ptr); + + const char *suffix = NULL; + if (m_type_bit_size == 32) + suffix = "f"; + + if (suffix) + { + char *name2 = concat (name, suffix, NULL); + free (name); + name = name2; + } + + hsa_sanitize_name (name); + return name; +} + +unsigned +hsa_internal_fn::get_arity () +{ + switch (m_fn) + { + case IFN_ACOS: + case IFN_ASIN: + case IFN_ATAN: + case IFN_COS: + case IFN_EXP: + case IFN_EXP10: + case IFN_EXP2: + case IFN_EXPM1: + case IFN_LOG: + case IFN_LOG10: + case IFN_LOG1P: + case IFN_LOG2: + case IFN_LOGB: + case IFN_SIGNIFICAND: + case IFN_SIN: + case IFN_SQRT: + case IFN_TAN: + case IFN_CEIL: + case IFN_FLOOR: + case IFN_NEARBYINT: + case IFN_RINT: + case IFN_ROUND: + case IFN_TRUNC: + return 1; + case IFN_ATAN2: + case IFN_COPYSIGN: + case IFN_FMOD: + case IFN_POW: + case IFN_REMAINDER: + case IFN_SCALB: + case IFN_LDEXP: + return 2; + case IFN_CLRSB: + case IFN_CLZ: + case IFN_CTZ: + case IFN_FFS: + case IFN_PARITY: + case IFN_POPCOUNT: + default: + /* As we produce sorry message for unknown internal functions, + reaching this label is definitely a bug. */ + gcc_unreachable (); + } +} + +BrigType16_t +hsa_internal_fn::get_argument_type (int n) +{ + switch (m_fn) + { + case IFN_ACOS: + case IFN_ASIN: + case IFN_ATAN: + case IFN_COS: + case IFN_EXP: + case IFN_EXP10: + case IFN_EXP2: + case IFN_EXPM1: + case IFN_LOG: + case IFN_LOG10: + case IFN_LOG1P: + case IFN_LOG2: + case IFN_LOGB: + case IFN_SIGNIFICAND: + case IFN_SIN: + case IFN_SQRT: + case IFN_TAN: + case IFN_CEIL: + case IFN_FLOOR: + case IFN_NEARBYINT: + case IFN_RINT: + case IFN_ROUND: + case IFN_TRUNC: + case IFN_ATAN2: + case IFN_COPYSIGN: + case IFN_FMOD: + case IFN_POW: + case IFN_REMAINDER: + case IFN_SCALB: + return hsa_float_for_bitsize (m_type_bit_size); + case IFN_LDEXP: + { + if (n == -1 || n == 0) + return hsa_float_for_bitsize (m_type_bit_size); + else + return BRIG_TYPE_S32; + } + default: + /* As we produce sorry message for unknown internal functions, + reaching this label is definitely a bug. */ + gcc_unreachable (); + } +} + +#include "gt-hsa-common.h" diff --git a/gcc/hsa-common.h b/gcc/hsa-common.h new file mode 100644 index 00000000000..a24bf6e5ad1 --- /dev/null +++ b/gcc/hsa-common.h @@ -0,0 +1,1412 @@ +/* HSAIL and BRIG related macros and definitions. + Copyright (C) 2013-2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef HSA_H +#define HSA_H + +#include "hsa-brig-format.h" +#include "is-a.h" +#include "predict.h" +#include "tree.h" +#include "vec.h" +#include "hash-table.h" +#include "basic-block.h" + + +/* Return true if the compiler should produce HSAIL. */ + +static inline bool +hsa_gen_requested_p (void) +{ +#ifndef ENABLE_HSA + return false; +#endif + return !flag_disable_hsa; +} + +/* Standard warning message if we failed to generate HSAIL for a function. */ + +#define HSA_SORRY_MSG "could not emit HSAIL for the function" + +class hsa_op_immed; +class hsa_op_cst_list; +class hsa_insn_basic; +class hsa_op_address; +class hsa_op_reg; +class hsa_bb; + +/* Class representing an input argument, output argument (result) or a + variable, that will eventually end up being a symbol directive. */ + +struct hsa_symbol +{ + /* Constructor. */ + hsa_symbol (BrigType16_t type, BrigSegment8_t segment, + BrigLinkage8_t linkage, bool global_scope_p = false, + BrigAllocation allocation = BRIG_ALLOCATION_AUTOMATIC, + BrigAlignment8_t align = BRIG_ALIGNMENT_8); + + /* Return total size of the symbol. */ + unsigned HOST_WIDE_INT total_byte_size (); + + /* Fill in those values into the symbol according to DECL, which are + determined independently from whether it is parameter, result, + or a variable, local or global. */ + void fillup_for_decl (tree decl); + + /* Pointer to the original tree, which is PARM_DECL for input parameters and + RESULT_DECL for the output parameters. Also can be CONST_DECL for Fortran + constants which need to be put into readonly segment. */ + tree m_decl; + + /* Name of the symbol, that will be written into output and dumps. Can be + NULL, see name_number below. */ + const char *m_name; + + /* If name is NULL, artificial name will be formed from the segment name and + this number. */ + int m_name_number; + + /* Once written, this is the offset of the associated symbol directive. Zero + means the symbol has not been written yet. */ + unsigned m_directive_offset; + + /* HSA type of the parameter. */ + BrigType16_t m_type; + + /* The HSA segment this will eventually end up in. */ + BrigSegment8_t m_segment; + + /* The HSA kind of linkage. */ + BrigLinkage8_t m_linkage; + + /* Array dimension, if non-zero. */ + unsigned HOST_WIDE_INT m_dim; + + /* Constant value, used for string constants. */ + hsa_op_immed *m_cst_value; + + /* Is in global scope. */ + bool m_global_scope_p; + + /* True if an error has been seen for the symbol. */ + bool m_seen_error; + + /* Symbol allocation. */ + BrigAllocation m_allocation; + + /* Flag used for global variables if a variable is already emitted or not. */ + bool m_emitted_to_brig; + + /* Alignment of the symbol. */ + BrigAlignment8_t m_align; + +private: + /* Default constructor. */ + hsa_symbol (); +}; + +/* Abstract class for HSA instruction operands. */ + +class hsa_op_base +{ +public: + /* Next operand scheduled to be written when writing BRIG operand + section. */ + hsa_op_base *m_next; + + /* Offset to which the associated operand structure will be written. Zero if + yet not scheduled for writing. */ + unsigned m_brig_op_offset; + + /* The type of a particular operand. */ + BrigKind16_t m_kind; + +protected: + hsa_op_base (BrigKind16_t k); +private: + /* Make the default constructor inaccessible. */ + hsa_op_base () {} +}; + +/* Common abstract ancestor for operands which have a type. */ + +class hsa_op_with_type : public hsa_op_base +{ +public: + /* The type. */ + BrigType16_t m_type; + + /* Convert an operand to a destination type DTYPE and attach insns + to HBB if needed. */ + hsa_op_with_type *get_in_type (BrigType16_t dtype, hsa_bb *hbb); + +protected: + hsa_op_with_type (BrigKind16_t k, BrigType16_t t); +private: + /* Make the default constructor inaccessible. */ + hsa_op_with_type () : hsa_op_base (BRIG_KIND_NONE) {} +}; + +/* An immediate HSA operand. */ + +class hsa_op_immed : public hsa_op_with_type +{ +public: + hsa_op_immed (tree tree_val, bool min32int = true); + hsa_op_immed (HOST_WIDE_INT int_value, BrigType16_t type); + void *operator new (size_t); + ~hsa_op_immed (); + void set_type (BrigKind16_t t); + + /* Function returns pointer to a buffer that contains binary representation + of the immeadiate value. The buffer has length of BRIG_SIZE and + a caller is responsible for deallocation of the buffer. */ + char *emit_to_buffer (unsigned *brig_size); + + /* Value as represented by middle end. */ + tree m_tree_value; + + /* Integer value representation. */ + HOST_WIDE_INT m_int_value; + +private: + /* Make the default constructor inaccessible. */ + hsa_op_immed (); + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} +}; + +/* Report whether or not P is a an immediate operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_base *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_CONSTANT_BYTES; +} + +/* Likewise, but for a more specified base. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_with_type *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_CONSTANT_BYTES; +} + + +/* HSA register operand. */ + +class hsa_op_reg : public hsa_op_with_type +{ + friend class hsa_insn_basic; + friend class hsa_insn_phi; +public: + hsa_op_reg (BrigType16_t t); + void *operator new (size_t); + + /* Verify register operand. */ + void verify_ssa (); + + /* If NON-NULL, gimple SSA that we come from. NULL if none. */ + tree m_gimple_ssa; + + /* Defining instruction while still in the SSA. */ + hsa_insn_basic *m_def_insn; + + /* If the register allocator decides to spill the register, this is the + appropriate spill symbol. */ + hsa_symbol *m_spill_sym; + + /* Number of this register structure in the order in which they were + allocated. */ + int m_order; + int m_lr_begin, m_lr_end; + + /* Zero if the register is not yet allocated. After, allocation, this must + be 'c', 's', 'd' or 'q'. */ + char m_reg_class; + /* If allocated, the number of the HW register (within its HSA register + class). */ + char m_hard_num; + +private: + /* Make the default constructor inaccessible. */ + hsa_op_reg () : hsa_op_with_type (BRIG_KIND_NONE, BRIG_TYPE_NONE) {} + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} + /* Set definition where the register is defined. */ + void set_definition (hsa_insn_basic *insn); + /* Uses of the value while still in SSA. */ + auto_vec m_uses; +}; + +/* Report whether or not P is a register operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_base *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_REGISTER; +} + +/* Report whether or not P is a register operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_with_type *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_REGISTER; +} + +/* An address HSA operand. */ + +class hsa_op_address : public hsa_op_base +{ +public: + /* set up a new address operand consisting of base symbol SYM, register R and + immediate OFFSET. If the machine model is not large and offset is 64 bit, + the upper, 32 bits have to be zero. */ + hsa_op_address (hsa_symbol *sym, hsa_op_reg *reg, + HOST_WIDE_INT offset = 0); + + void *operator new (size_t); + + /* Set up a new address operand consisting of base symbol SYM and + immediate OFFSET. If the machine model is not large and offset is 64 bit, + the upper, 32 bits have to be zero. */ + hsa_op_address (hsa_symbol *sym, HOST_WIDE_INT offset = 0); + + /* Set up a new address operand consisting of register R and + immediate OFFSET. If the machine model is not large and offset is 64 bit, + the upper, 32 bits have to be zero. */ + hsa_op_address (hsa_op_reg *reg, HOST_WIDE_INT offset = 0); + + /* Symbol base of the address. Can be NULL if there is none. */ + hsa_symbol *m_symbol; + + /* Register offset. Can be NULL if there is none. */ + hsa_op_reg *m_reg; + + /* Immediate byte offset. */ + HOST_WIDE_INT m_imm_offset; + +private: + /* Make the default constructor inaccessible. */ + hsa_op_address () : hsa_op_base (BRIG_KIND_NONE) {} + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} +}; + +/* Report whether or not P is an address operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_base *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_ADDRESS; +} + +/* A reference to code HSA operand. It can be either reference + to a start of a BB or a start of a function. */ + +class hsa_op_code_ref : public hsa_op_base +{ +public: + hsa_op_code_ref (); + + /* Offset in the code section that this refers to. */ + unsigned m_directive_offset; +}; + +/* Report whether or not P is a code reference operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_base *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_CODE_REF; +} + +/* Code list HSA operand. */ + +class hsa_op_code_list: public hsa_op_base +{ +public: + hsa_op_code_list (unsigned elements); + void *operator new (size_t); + + /* Offset to variable-sized array in hsa_data section, where + are offsets to entries in the hsa_code section. */ + auto_vec m_offsets; +private: + /* Make the default constructor inaccessible. */ + hsa_op_code_list () : hsa_op_base (BRIG_KIND_NONE) {} + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} +}; + +/* Report whether or not P is a code list operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_base *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_CODE_LIST; +} + +/* Operand list HSA operand. */ + +class hsa_op_operand_list: public hsa_op_base +{ +public: + hsa_op_operand_list (unsigned elements); + ~hsa_op_operand_list (); + void *operator new (size_t); + + /* Offset to variable-sized array in hsa_data section, where + are offsets to entries in the hsa_code section. */ + auto_vec m_offsets; +private: + /* Make the default constructor inaccessible. */ + hsa_op_operand_list () : hsa_op_base (BRIG_KIND_NONE) {} + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} +}; + +/* Report whether or not P is a code list operand. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_op_base *p) +{ + return p->m_kind == BRIG_KIND_OPERAND_OPERAND_LIST; +} + +/* Opcodes of instructions that are not part of HSA but that we use to + represent it nevertheless. */ + +#define HSA_OPCODE_PHI (-1) +#define HSA_OPCODE_ARG_BLOCK (-2) + +/* The number of operand pointers we can directly in an instruction. */ +#define HSA_BRIG_INT_STORAGE_OPERANDS 5 + +/* Class representing an HSA instruction. Unlike typical ancestors for + specialized classes, this one is also directly used for all instructions + that are then represented as BrigInstBasic. */ + +class hsa_insn_basic +{ +public: + hsa_insn_basic (unsigned nops, int opc); + hsa_insn_basic (unsigned nops, int opc, BrigType16_t t, + hsa_op_base *arg0 = NULL, + hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL, + hsa_op_base *arg3 = NULL); + + void *operator new (size_t); + void set_op (int index, hsa_op_base *op); + hsa_op_base *get_op (int index); + hsa_op_base **get_op_addr (int index); + unsigned int operand_count (); + void verify (); + unsigned input_count (); + unsigned num_used_ops (); + void set_output_in_type (hsa_op_reg *dest, unsigned op_index, hsa_bb *hbb); + bool op_output_p (unsigned opnum); + + /* The previous and next instruction in the basic block. */ + hsa_insn_basic *m_prev, *m_next; + + /* Basic block this instruction belongs to. */ + basic_block m_bb; + + /* Operand code distinguishing different types of instructions. Eventually + these should only be BRIG_INST_* values from the BrigOpcode16_t range but + initially we use negative values for PHI nodes and such. */ + int m_opcode; + + /* Linearized number assigned to the instruction by HSA RA. */ + int m_number; + + /* Type of the destination of the operations. */ + BrigType16_t m_type; + + /* BRIG offset of the instruction in code section. */ + unsigned int m_brig_offset; + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_basic () {} + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} + /* The individual operands. All instructions but PHI nodes have five or + fewer instructions and so will fit the internal storage. */ + /* TODO: Vast majority of instructions have three or fewer operands, so we + may actually try reducing it. */ + auto_vec m_operands; +}; + +/* Class representing a PHI node of the SSA form of HSA virtual + registers. */ + +class hsa_insn_phi : public hsa_insn_basic +{ +public: + hsa_insn_phi (unsigned nops, hsa_op_reg *dst); + + /* Destination. */ + hsa_op_reg *m_dest; + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_phi () : hsa_insn_basic (1, HSA_OPCODE_PHI) {} +}; + +/* Report whether or not P is a PHI node. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return p->m_opcode == HSA_OPCODE_PHI; +} + +/* HSA instruction for */ +class hsa_insn_br : public hsa_insn_basic +{ +public: + hsa_insn_br (unsigned nops, int opc, BrigType16_t t, BrigWidth8_t width, + hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); + + /* Number of work-items affected in the same way by the instruction. */ + BrigWidth8_t m_width; + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_br () : hsa_insn_basic (0, BRIG_OPCODE_BR) {} +}; + +/* Return true if P is a branching/synchronization instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return p->m_opcode == BRIG_OPCODE_BARRIER + || p->m_opcode == BRIG_OPCODE_BR; +} + +/* HSA instruction for conditional branches. Structurally the same as + hsa_insn_br but we represent it specially because of inherent control + flow it represents. */ + +class hsa_insn_cbr : public hsa_insn_br +{ +public: + hsa_insn_cbr (hsa_op_reg *ctrl); + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_cbr () : hsa_insn_br (0, BRIG_OPCODE_CBR, BRIG_TYPE_B1, + BRIG_WIDTH_1) {} +}; + +/* Report whether P is a contitional branching instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return p->m_opcode == BRIG_OPCODE_CBR; +} + +/* HSA instruction for switch branches. */ + +class hsa_insn_sbr : public hsa_insn_basic +{ +public: + hsa_insn_sbr (hsa_op_reg *index, unsigned jump_count); + + /* Default destructor. */ + ~hsa_insn_sbr (); + + void replace_all_labels (basic_block old_bb, basic_block new_bb); + + /* Width as described in HSA documentation. */ + BrigWidth8_t m_width; + + /* Jump table. */ + vec m_jump_table; + + /* Code list for label references. */ + hsa_op_code_list *m_label_code_list; + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_sbr () : hsa_insn_basic (1, BRIG_OPCODE_SBR) {} +}; + +/* Report whether P is a switch branching instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return p->m_opcode == BRIG_OPCODE_SBR; +} + +/* HSA instruction for comparisons. */ + +class hsa_insn_cmp : public hsa_insn_basic +{ +public: + hsa_insn_cmp (BrigCompareOperation8_t cmp, BrigType16_t t, + hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL); + + /* Source type should be derived from operand types. */ + + /* The comparison operation. */ + BrigCompareOperation8_t m_compare; + + /* TODO: Modifiers and packing control are missing but so are everywhere + else. */ +private: + /* Make the default constructor inaccessible. */ + hsa_insn_cmp () : hsa_insn_basic (1, BRIG_OPCODE_CMP) {} +}; + +/* Report whether or not P is a comparison instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return p->m_opcode == BRIG_OPCODE_CMP; +} + +/* HSA instruction for memory operations. */ + +class hsa_insn_mem : public hsa_insn_basic +{ +public: + hsa_insn_mem (int opc, BrigType16_t t, hsa_op_base *arg0, hsa_op_base *arg1); + + /* Set alignment to VALUE. */ + + void set_align (BrigAlignment8_t value); + + /* The segment is of the memory access is either the segment of the symbol in + the address operand or flat address is there is no symbol there. */ + + /* Required alignment of the memory operation. */ + BrigAlignment8_t m_align; + + /* HSA equiv class, basically an alias set number. */ + uint8_t m_equiv_class; + + /* TODO: Add width modifier, perhaps also other things. */ +protected: + hsa_insn_mem (unsigned nops, int opc, BrigType16_t t, + hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_mem () : hsa_insn_basic (1, BRIG_OPCODE_LD) {} +}; + +/* Report whether or not P is a memory instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_LD + || p->m_opcode == BRIG_OPCODE_ST); +} + +/* HSA instruction for atomic operations. */ + +class hsa_insn_atomic : public hsa_insn_mem +{ +public: + hsa_insn_atomic (int nops, int opc, enum BrigAtomicOperation aop, + BrigType16_t t, BrigMemoryOrder memorder, + hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); + + /* The operation itself. */ + enum BrigAtomicOperation m_atomicop; + + /* Things like acquire/release/aligned. */ + enum BrigMemoryOrder m_memoryorder; + + /* Scope of the atomic operation. */ + enum BrigMemoryScope m_memoryscope; + +private: + /* Make the default constructor inaccessible. */ + hsa_insn_atomic () : hsa_insn_mem (1, BRIG_KIND_NONE, BRIG_TYPE_NONE) {} +}; + +/* Report whether or not P is an atomic instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_ATOMIC + || p->m_opcode == BRIG_OPCODE_ATOMICNORET); +} + +/* HSA instruction for signal operations. */ + +class hsa_insn_signal : public hsa_insn_basic +{ +public: + hsa_insn_signal (int nops, int opc, enum BrigAtomicOperation sop, + BrigType16_t t, BrigMemoryOrder memorder, + hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); + + /* Things like acquire/release/aligned. */ + enum BrigMemoryOrder m_memory_order; + + /* The operation itself. */ + enum BrigAtomicOperation m_signalop; +}; + +/* Report whether or not P is a signal instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_SIGNAL + || p->m_opcode == BRIG_OPCODE_SIGNALNORET); +} + +/* HSA instruction to convert between flat addressing and segments. */ + +class hsa_insn_seg : public hsa_insn_basic +{ +public: + hsa_insn_seg (int opc, BrigType16_t destt, BrigType16_t srct, + BrigSegment8_t seg, hsa_op_base *arg0, hsa_op_base *arg1); + + /* Source type. Depends on the source addressing/segment. */ + BrigType16_t m_src_type; + /* The segment we are converting from or to. */ + BrigSegment8_t m_segment; +private: + /* Make the default constructor inaccessible. */ + hsa_insn_seg () : hsa_insn_basic (1, BRIG_OPCODE_STOF) {} +}; + +/* Report whether or not P is a segment conversion instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_STOF + || p->m_opcode == BRIG_OPCODE_FTOS); +} + +/* Class for internal functions for purpose of HSA emission. */ + +class hsa_internal_fn +{ +public: + hsa_internal_fn (enum internal_fn fn, unsigned type_bit_size): + m_fn (fn), m_type_bit_size (type_bit_size), m_offset (0) {} + + hsa_internal_fn (const hsa_internal_fn *f): + m_fn (f->m_fn), m_type_bit_size (f->m_type_bit_size), + m_offset (f->m_offset) {} + + /* Return arity of the internal function. */ + unsigned get_arity (); + + /* Return BRIG type of N-th argument, if -1 is passed, return value type + is received. */ + BrigType16_t get_argument_type (int n); + + /* Return function name. The memory must be released by a caller. */ + char *name (); + + /* Internal function. */ + enum internal_fn m_fn; + + /* Bit width of return type. */ + unsigned m_type_bit_size; + + /* BRIG offset of declaration of the function. */ + BrigCodeOffset32_t m_offset; +}; + +/* HSA instruction for function call. */ + +class hsa_insn_call : public hsa_insn_basic +{ +public: + hsa_insn_call (tree callee); + hsa_insn_call (hsa_internal_fn *fn); + + /* Default destructor. */ + ~hsa_insn_call (); + + /* Called function. */ + tree m_called_function; + + /* Called internal function. */ + hsa_internal_fn *m_called_internal_fn; + + /* Input formal arguments. */ + auto_vec m_input_args; + + /* Input arguments store instructions. */ + auto_vec m_input_arg_insns; + + /* Output argument, can be NULL for void functions. */ + hsa_symbol *m_output_arg; + + /* Called function code reference. */ + hsa_op_code_ref m_func; + + /* Code list for arguments of the function. */ + hsa_op_code_list *m_args_code_list; + + /* Code list for result of the function. */ + hsa_op_code_list *m_result_code_list; +private: + /* Make the default constructor inaccessible. */ + hsa_insn_call () : hsa_insn_basic (0, BRIG_OPCODE_CALL) {} +}; + +/* Report whether or not P is a call instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_CALL); +} + +/* HSA call instruction block encapsulates definition of arguments, + result type, corresponding loads and a possible store. + Moreover, it contains a single call instruction. + Emission of the instruction will produce multiple + HSAIL instructions. */ + +class hsa_insn_arg_block : public hsa_insn_basic +{ +public: + hsa_insn_arg_block (BrigKind brig_kind, hsa_insn_call * call); + + /* Kind of argument block. */ + BrigKind m_kind; + + /* Call instruction. */ + hsa_insn_call *m_call_insn; +}; + +/* Report whether or not P is a call block instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == HSA_OPCODE_ARG_BLOCK); +} + +/* HSA comment instruction. */ + +class hsa_insn_comment: public hsa_insn_basic +{ +public: + /* Constructor of class representing the comment in HSAIL. */ + hsa_insn_comment (const char *s); + + /* Default destructor. */ + ~hsa_insn_comment (); + + char *m_comment; +}; + +/* Report whether or not P is a call block instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_KIND_DIRECTIVE_COMMENT); +} + +/* HSA queue instruction. */ + +class hsa_insn_queue: public hsa_insn_basic +{ +public: + hsa_insn_queue (int nops, int opcode, BrigSegment segment, + BrigMemoryOrder memory_order, + hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, + hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); + + /* Destructor. */ + ~hsa_insn_queue (); + + /* Segment used to refer to the queue. Must be global or flat. */ + BrigSegment m_segment; + /* Memory order used to specify synchronization. */ + BrigMemoryOrder m_memory_order; +}; + +/* Report whether or not P is a queue instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_ADDQUEUEWRITEINDEX + || p->m_opcode == BRIG_OPCODE_CASQUEUEWRITEINDEX + || p->m_opcode == BRIG_OPCODE_LDQUEUEREADINDEX + || p->m_opcode == BRIG_OPCODE_LDQUEUEWRITEINDEX + || p->m_opcode == BRIG_OPCODE_STQUEUEREADINDEX + || p->m_opcode == BRIG_OPCODE_STQUEUEWRITEINDEX); +} + +/* HSA source type instruction. */ + +class hsa_insn_srctype: public hsa_insn_basic +{ +public: + hsa_insn_srctype (int nops, BrigOpcode opcode, BrigType16_t destt, + BrigType16_t srct, hsa_op_base *arg0, hsa_op_base *arg1, + hsa_op_base *arg2); + + /* Source type. */ + BrigType16_t m_source_type; + + /* Destructor. */ + ~hsa_insn_srctype (); +}; + +/* Report whether or not P is a source type instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_POPCOUNT + || p->m_opcode == BRIG_OPCODE_FIRSTBIT + || p->m_opcode == BRIG_OPCODE_LASTBIT); +} + +/* HSA packed instruction. */ + +class hsa_insn_packed : public hsa_insn_srctype +{ +public: + hsa_insn_packed (int nops, BrigOpcode opcode, BrigType16_t destt, + BrigType16_t srct, hsa_op_base *arg0, hsa_op_base *arg1, + hsa_op_base *arg2); + + /* Operand list for an operand of the instruction. */ + hsa_op_operand_list *m_operand_list; + + /* Destructor. */ + ~hsa_insn_packed (); +}; + +/* Report whether or not P is a combine instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_COMBINE + || p->m_opcode == BRIG_OPCODE_EXPAND); +} + +/* HSA convert instruction. */ + +class hsa_insn_cvt: public hsa_insn_basic +{ +public: + hsa_insn_cvt (hsa_op_with_type *dest, hsa_op_with_type *src); +}; + +/* Report whether or not P is a convert instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_CVT); +} + +/* HSA alloca instruction. */ + +class hsa_insn_alloca: public hsa_insn_basic +{ +public: + hsa_insn_alloca (hsa_op_with_type *dest, hsa_op_with_type *size, + unsigned alignment = 0); + + /* Required alignment of the allocation. */ + BrigAlignment8_t m_align; +}; + +/* Report whether or not P is an alloca instruction. */ + +template <> +template <> +inline bool +is_a_helper ::test (hsa_insn_basic *p) +{ + return (p->m_opcode == BRIG_OPCODE_ALLOCA); +} + +/* Basic block of HSA instructions. */ + +class hsa_bb +{ +public: + hsa_bb (basic_block cfg_bb); + hsa_bb (basic_block cfg_bb, int idx); + ~hsa_bb (); + + /* Append an instruction INSN into the basic block. */ + void append_insn (hsa_insn_basic *insn); + + /* Add a PHI instruction. */ + void append_phi (hsa_insn_phi *phi); + + /* The real CFG BB that this HBB belongs to. */ + basic_block m_bb; + + /* The operand that refers to the label to this BB. */ + hsa_op_code_ref m_label_ref; + + /* The first and last instruction. */ + hsa_insn_basic *m_first_insn, *m_last_insn; + /* The first and last phi node. */ + hsa_insn_phi *m_first_phi, *m_last_phi; + + /* Just a number to construct names from. */ + int m_index; + + bitmap m_liveout, m_livein; +private: + /* Make the default constructor inaccessible. */ + hsa_bb (); + /* All objects are deallocated by destroying their pool, so make delete + inaccessible too. */ + void operator delete (void *) {} +}; + +/* Return the corresponding HSA basic block structure for the given control + flow basic_block BB. */ + +static inline hsa_bb * +hsa_bb_for_bb (basic_block bb) +{ + return (struct hsa_bb *) bb->aux; +} + +/* Class for hashing local hsa_symbols. */ + +struct hsa_noop_symbol_hasher : nofree_ptr_hash +{ + static inline hashval_t hash (const value_type); + static inline bool equal (const value_type, const compare_type); +}; + +/* Hash hsa_symbol. */ + +inline hashval_t +hsa_noop_symbol_hasher::hash (const value_type item) +{ + return DECL_UID (item->m_decl); +} + +/* Return true if the DECL_UIDs of decls both symbols refer to are equal. */ + +inline bool +hsa_noop_symbol_hasher::equal (const value_type a, const compare_type b) +{ + return (DECL_UID (a->m_decl) == DECL_UID (b->m_decl)); +} + +/* Structure that encapsulates intermediate representation of a HSA + function. */ + +class hsa_function_representation +{ +public: + hsa_function_representation (tree fdecl, bool kernel_p, + unsigned ssa_names_count, + bool modified_cfg = false); + hsa_function_representation (hsa_internal_fn *fn); + ~hsa_function_representation (); + + /* Builds a shadow register that is utilized to a kernel dispatch. */ + hsa_op_reg *get_shadow_reg (); + + /* Return true if we are in a function that has kernel dispatch + shadow register. */ + bool has_shadow_reg_p (); + + /* The entry/exit blocks don't contain incoming code, + but the HSA generator might use them to put code into, + so we need hsa_bb instances of them. */ + void init_extra_bbs (); + + /* Update CFG dominators if m_modified_cfg flag is set. */ + void update_dominance (); + + /* Return linkage of the representation. */ + BrigLinkage8_t get_linkage (); + + /* Create a private symbol of requested TYPE. */ + hsa_symbol *create_hsa_temporary (BrigType16_t type); + + /* Lookup or create a HSA pseudo register for a given gimple SSA name. */ + hsa_op_reg *reg_for_gimple_ssa (tree ssa); + + /* Name of the function. */ + char *m_name; + + /* Number of allocated register structures. */ + int m_reg_count; + + /* Input arguments. */ + vec m_input_args; + + /* Output argument or NULL if there is none. */ + hsa_symbol *m_output_arg; + + /* Hash table of local variable symbols. */ + hash_table *m_local_symbols; + + /* Hash map for string constants. */ + hash_map m_string_constants_map; + + /* Vector of pointers to spill symbols. */ + vec m_spill_symbols; + + /* Vector of pointers to global variables and transformed string constants + that are used by the function. */ + vec m_global_symbols; + + /* Private function artificial variables. */ + vec m_private_variables; + + /* Vector of called function declarations. */ + vec m_called_functions; + + /* Vector of used internal functions. */ + vec m_called_internal_fns; + + /* Number of HBB BBs. */ + int m_hbb_count; + + /* Whether or not we could check and enforce SSA properties. */ + bool m_in_ssa; + + /* True if the function is kernel function. */ + bool m_kern_p; + + /* True if the function representation is a declaration. */ + bool m_declaration_p; + + /* Function declaration tree. */ + tree m_decl; + + /* Internal function info is used for declarations of internal functions. */ + hsa_internal_fn *m_internal_fn; + + /* Runtime shadow register. */ + hsa_op_reg *m_shadow_reg; + + /* Number of kernel dispatched which take place in the function. */ + unsigned m_kernel_dispatch_count; + + /* If the function representation contains a kernel dispatch, + OMP data size is necessary memory that is used for copying before + a kernel dispatch. */ + unsigned m_maximum_omp_data_size; + + /* Return true if there's an HSA-specific warning already seen. */ + bool m_seen_error; + + /* Counter for temporary symbols created in the function representation. */ + unsigned m_temp_symbol_count; + + /* SSA names mapping. */ + vec m_ssa_map; + + /* Flag whether a function needs update of dominators before RA. */ + bool m_modified_cfg; +}; + +enum hsa_function_kind +{ + HSA_NONE, + HSA_KERNEL, + HSA_FUNCTION +}; + +struct hsa_function_summary +{ + /* Default constructor. */ + hsa_function_summary (); + + /* Kind of GPU/host function. */ + hsa_function_kind m_kind; + + /* Pointer to a cgraph node which is a HSA implementation of the function. + In case of the function is a HSA function, the bound function points + to the host function. */ + cgraph_node *m_bound_function; + + /* Identifies if the function is an HSA function or a host function. */ + bool m_gpu_implementation_p; + + /* True if the function is a gridified kernel. */ + bool m_gridified_kernel_p; +}; + +inline +hsa_function_summary::hsa_function_summary (): m_kind (HSA_NONE), + m_bound_function (NULL), m_gpu_implementation_p (false) +{ +} + +/* Function summary for HSA functions. */ +class hsa_summary_t: public function_summary +{ +public: + hsa_summary_t (symbol_table *table): + function_summary (table) { } + + /* Couple GPU and HOST as gpu-specific and host-specific implementation of + the same function. KIND determines whether GPU is a host-invokable kernel + or gpu-callable function and GRIDIFIED_KERNEL_P is set if the function was + gridified in OMP. */ + + void link_functions (cgraph_node *gpu, cgraph_node *host, + hsa_function_kind kind, bool gridified_kernel_p); + +private: + void process_gpu_implementation_attributes (tree gdecl); +}; + +/* OMP simple builtin describes behavior that should be done for + the routine. */ +class omp_simple_builtin +{ +public: + omp_simple_builtin (const char *name, const char *warning_message, + bool sorry, hsa_op_immed *return_value = NULL): + m_name (name), m_warning_message (warning_message), m_sorry (sorry), + m_return_value (return_value) + {} + + /* Generate HSAIL instructions for the builtin or produce warning message. */ + void generate (gimple *stmt, hsa_bb *hbb); + + /* Name of function. */ + const char *m_name; + + /* Warning message. */ + const char *m_warning_message; + + /* Flag if we should sorry after the warning message is printed. */ + bool m_sorry; + + /* Return value of the function. */ + hsa_op_immed *m_return_value; + + /* Emission function. */ + void (*m_emit_func) (gimple *stmt, hsa_bb *); +}; + +/* Class for hashing hsa_internal_fn. */ + +struct hsa_internal_fn_hasher: free_ptr_hash +{ + static inline hashval_t hash (const value_type); + static inline bool equal (const value_type, const compare_type); +}; + +/* Hash hsa_symbol. */ + +inline hashval_t +hsa_internal_fn_hasher::hash (const value_type item) +{ + return item->m_fn; +} + +/* Return true if the DECL_UIDs of decls both symbols refer to are equal. */ + +inline bool +hsa_internal_fn_hasher::equal (const value_type a, const compare_type b) +{ + return a->m_fn == b->m_fn && a->m_type_bit_size == b->m_type_bit_size; +} + +/* in hsa-common.c */ +extern struct hsa_function_representation *hsa_cfun; +extern hash_map *> *hsa_decl_kernel_dependencies; +extern hsa_summary_t *hsa_summaries; +extern hsa_symbol *hsa_num_threads; +extern unsigned hsa_kernel_calls_counter; +extern hash_set *hsa_failed_functions; +extern hash_table *hsa_global_variable_symbols; + +bool hsa_callable_function_p (tree fndecl); +void hsa_init_compilation_unit_data (void); +void hsa_deinit_compilation_unit_data (void); +bool hsa_machine_large_p (void); +bool hsa_full_profile_p (void); +bool hsa_opcode_floating_bit_insn_p (BrigOpcode16_t); +unsigned hsa_type_bit_size (BrigType16_t t); +BrigType16_t hsa_bittype_for_bitsize (unsigned bitsize); +BrigType16_t hsa_uint_for_bitsize (unsigned bitsize); +BrigType16_t hsa_float_for_bitsize (unsigned bitsize); +BrigType16_t hsa_bittype_for_type (BrigType16_t t); +BrigType16_t hsa_unsigned_type_for_type (BrigType16_t t); +bool hsa_type_packed_p (BrigType16_t type); +bool hsa_type_float_p (BrigType16_t type); +bool hsa_type_integer_p (BrigType16_t type); +bool hsa_btype_p (BrigType16_t type); +BrigAlignment8_t hsa_alignment_encoding (unsigned n); +BrigAlignment8_t hsa_natural_alignment (BrigType16_t type); +BrigAlignment8_t hsa_object_alignment (tree t); +unsigned hsa_byte_alignment (BrigAlignment8_t alignment); +void hsa_destroy_operand (hsa_op_base *op); +void hsa_destroy_insn (hsa_insn_basic *insn); +void hsa_add_kern_decl_mapping (tree decl, char *name, unsigned, bool); +unsigned hsa_get_number_decl_kernel_mappings (void); +tree hsa_get_decl_kernel_mapping_decl (unsigned i); +char *hsa_get_decl_kernel_mapping_name (unsigned i); +unsigned hsa_get_decl_kernel_mapping_omp_size (unsigned i); +bool hsa_get_decl_kernel_mapping_gridified (unsigned i); +void hsa_free_decl_kernel_mapping (void); +tree *hsa_get_ctor_statements (void); +tree *hsa_get_dtor_statements (void); +tree *hsa_get_kernel_dispatch_type (void); +void hsa_add_kernel_dependency (tree caller, const char *called_function); +void hsa_sanitize_name (char *p); +char *hsa_brig_function_name (const char *p); +const char *hsa_get_declaration_name (tree decl); +void hsa_register_kernel (cgraph_node *host); +void hsa_register_kernel (cgraph_node *gpu, cgraph_node *host); +bool hsa_seen_error (void); +void hsa_fail_cfun (void); + +/* In hsa-gen.c. */ +void hsa_build_append_simple_mov (hsa_op_reg *, hsa_op_base *, hsa_bb *); +hsa_symbol *hsa_get_spill_symbol (BrigType16_t); +hsa_symbol *hsa_get_string_cst_symbol (BrigType16_t); +hsa_op_reg *hsa_spill_in (hsa_insn_basic *, hsa_op_reg *, hsa_op_reg **); +hsa_op_reg *hsa_spill_out (hsa_insn_basic *, hsa_op_reg *, hsa_op_reg **); +hsa_bb *hsa_init_new_bb (basic_block); +hsa_function_representation *hsa_generate_function_declaration (tree decl); +hsa_function_representation *hsa_generate_internal_fn_decl (hsa_internal_fn *); +tree hsa_get_host_function (tree decl); + +/* In hsa-regalloc.c. */ +void hsa_regalloc (void); + +/* In hsa-brig.c. */ +extern hash_table *hsa_emitted_internal_decls; +void hsa_brig_emit_function (void); +void hsa_output_brig (void); +unsigned hsa_get_imm_brig_type_len (BrigType16_t type); +void hsa_brig_emit_omp_symbols (void); + +/* In hsa-dump.c. */ +const char *hsa_seg_name (BrigSegment8_t); +void dump_hsa_insn (FILE *f, hsa_insn_basic *insn); +void dump_hsa_bb (FILE *, hsa_bb *); +void dump_hsa_cfun (FILE *); +DEBUG_FUNCTION void debug_hsa_operand (hsa_op_base *opc); +DEBUG_FUNCTION void debug_hsa_insn (hsa_insn_basic *insn); + +union hsa_bytes +{ + uint8_t b8; + uint16_t b16; + uint32_t b32; + uint64_t b64; +}; + +/* Return true if a function DECL is an HSA implementation. */ + +static inline bool +hsa_gpu_implementation_p (tree decl) +{ + if (hsa_summaries == NULL) + return false; + + hsa_function_summary *s = hsa_summaries->get (cgraph_node::get_create (decl)); + + return s->m_gpu_implementation_p; +} + +#endif /* HSA_H */ diff --git a/gcc/hsa-dump.c b/gcc/hsa-dump.c index 1cd128ea3b4..e2ef58693c9 100644 --- a/gcc/hsa-dump.c +++ b/gcc/hsa-dump.c @@ -33,7 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "print-tree.h" #include "symbol-summary.h" -#include "hsa.h" +#include "hsa-common.h" /* Return textual name of TYPE. */ diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c index 632561d5e45..7721fcc9334 100644 --- a/gcc/hsa-gen.c +++ b/gcc/hsa-gen.c @@ -49,7 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "print-tree.h" #include "symbol-summary.h" -#include "hsa.h" +#include "hsa-common.h" #include "cfghooks.h" #include "tree-cfg.h" #include "cfgloop.h" diff --git a/gcc/hsa-regalloc.c b/gcc/hsa-regalloc.c index 5f2ac13c823..4d9441c91d4 100644 --- a/gcc/hsa-regalloc.c +++ b/gcc/hsa-regalloc.c @@ -35,7 +35,7 @@ along with GCC; see the file COPYING3. If not see #include "print-tree.h" #include "cfghooks.h" #include "symbol-summary.h" -#include "hsa.h" +#include "hsa-common.h" /* Process a PHI node PHI of basic block BB as a part of naive out-f-ssa. */ diff --git a/gcc/hsa.c b/gcc/hsa.c deleted file mode 100644 index 2035ce446a1..00000000000 --- a/gcc/hsa.c +++ /dev/null @@ -1,994 +0,0 @@ -/* Implementation of commonly needed HSAIL related functions and methods. - Copyright (C) 2013-2017 Free Software Foundation, Inc. - Contributed by Martin Jambor and - Martin Liska . - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "is-a.h" -#include "hash-set.h" -#include "hash-map.h" -#include "vec.h" -#include "tree.h" -#include "dumpfile.h" -#include "gimple-pretty-print.h" -#include "diagnostic-core.h" -#include "alloc-pool.h" -#include "cgraph.h" -#include "print-tree.h" -#include "stringpool.h" -#include "symbol-summary.h" -#include "hsa.h" -#include "internal-fn.h" -#include "ctype.h" -#include "builtins.h" - -/* Structure containing intermediate HSA representation of the generated - function. */ -class hsa_function_representation *hsa_cfun; - -/* Element of the mapping vector between a host decl and an HSA kernel. */ - -struct GTY(()) hsa_decl_kernel_map_element -{ - /* The decl of the host function. */ - tree decl; - /* Name of the HSA kernel in BRIG. */ - char * GTY((skip)) name; - /* Size of OMP data, if the kernel contains a kernel dispatch. */ - unsigned omp_data_size; - /* True if the function is gridified kernel. */ - bool gridified_kernel_p; -}; - -/* Mapping between decls and corresponding HSA kernels in this compilation - unit. */ - -static GTY (()) vec - *hsa_decl_kernel_mapping; - -/* Mapping between decls and corresponding HSA kernels - called by the function. */ -hash_map *> *hsa_decl_kernel_dependencies; - -/* Hash function to lookup a symbol for a decl. */ -hash_table *hsa_global_variable_symbols; - -/* HSA summaries. */ -hsa_summary_t *hsa_summaries = NULL; - -/* HSA number of threads. */ -hsa_symbol *hsa_num_threads = NULL; - -/* HSA function that cannot be expanded to HSAIL. */ -hash_set *hsa_failed_functions = NULL; - -/* True if compilation unit-wide data are already allocated and initialized. */ -static bool compilation_unit_data_initialized; - -/* Return true if FNDECL represents an HSA-callable function. */ - -bool -hsa_callable_function_p (tree fndecl) -{ - return (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl)) - && !lookup_attribute ("oacc function", DECL_ATTRIBUTES (fndecl))); -} - -/* Allocate HSA structures that are are used when dealing with different - functions. */ - -void -hsa_init_compilation_unit_data (void) -{ - if (compilation_unit_data_initialized) - return; - - compilation_unit_data_initialized = true; - - hsa_global_variable_symbols = new hash_table (8); - hsa_failed_functions = new hash_set (); - hsa_emitted_internal_decls = new hash_table (2); -} - -/* Free data structures that are used when dealing with different - functions. */ - -void -hsa_deinit_compilation_unit_data (void) -{ - gcc_assert (compilation_unit_data_initialized); - - delete hsa_failed_functions; - delete hsa_emitted_internal_decls; - - for (hash_table ::iterator it - = hsa_global_variable_symbols->begin (); - it != hsa_global_variable_symbols->end (); - ++it) - { - hsa_symbol *sym = *it; - delete sym; - } - - delete hsa_global_variable_symbols; - - if (hsa_num_threads) - { - delete hsa_num_threads; - hsa_num_threads = NULL; - } - - compilation_unit_data_initialized = false; -} - -/* Return true if we are generating large HSA machine model. */ - -bool -hsa_machine_large_p (void) -{ - /* FIXME: I suppose this is technically wrong but should work for me now. */ - return (GET_MODE_BITSIZE (Pmode) == 64); -} - -/* Return the HSA profile we are using. */ - -bool -hsa_full_profile_p (void) -{ - return true; -} - -/* Return true if a register in operand number OPNUM of instruction - is an output. False if it is an input. */ - -bool -hsa_insn_basic::op_output_p (unsigned opnum) -{ - switch (m_opcode) - { - case HSA_OPCODE_PHI: - case BRIG_OPCODE_CBR: - case BRIG_OPCODE_SBR: - case BRIG_OPCODE_ST: - case BRIG_OPCODE_SIGNALNORET: - case BRIG_OPCODE_DEBUGTRAP: - /* FIXME: There are probably missing cases here, double check. */ - return false; - case BRIG_OPCODE_EXPAND: - /* Example: expand_v4_b32_b128 (dest0, dest1, dest2, dest3), src0. */ - return opnum < operand_count () - 1; - default: - return opnum == 0; - } -} - -/* Return true if OPCODE is an floating-point bit instruction opcode. */ - -bool -hsa_opcode_floating_bit_insn_p (BrigOpcode16_t opcode) -{ - switch (opcode) - { - case BRIG_OPCODE_NEG: - case BRIG_OPCODE_ABS: - case BRIG_OPCODE_CLASS: - case BRIG_OPCODE_COPYSIGN: - return true; - default: - return false; - } -} - -/* Return the number of destination operands for this INSN. */ - -unsigned -hsa_insn_basic::input_count () -{ - switch (m_opcode) - { - default: - return 1; - - case BRIG_OPCODE_NOP: - return 0; - - case BRIG_OPCODE_EXPAND: - return 2; - - case BRIG_OPCODE_LD: - /* ld_v[234] not yet handled. */ - return 1; - - case BRIG_OPCODE_ST: - return 0; - - case BRIG_OPCODE_ATOMICNORET: - return 0; - - case BRIG_OPCODE_SIGNAL: - return 1; - - case BRIG_OPCODE_SIGNALNORET: - return 0; - - case BRIG_OPCODE_MEMFENCE: - return 0; - - case BRIG_OPCODE_RDIMAGE: - case BRIG_OPCODE_LDIMAGE: - case BRIG_OPCODE_STIMAGE: - case BRIG_OPCODE_QUERYIMAGE: - case BRIG_OPCODE_QUERYSAMPLER: - sorry ("HSA image ops not handled"); - return 0; - - case BRIG_OPCODE_CBR: - case BRIG_OPCODE_BR: - return 0; - - case BRIG_OPCODE_SBR: - return 0; /* ??? */ - - case BRIG_OPCODE_WAVEBARRIER: - return 0; /* ??? */ - - case BRIG_OPCODE_BARRIER: - case BRIG_OPCODE_ARRIVEFBAR: - case BRIG_OPCODE_INITFBAR: - case BRIG_OPCODE_JOINFBAR: - case BRIG_OPCODE_LEAVEFBAR: - case BRIG_OPCODE_RELEASEFBAR: - case BRIG_OPCODE_WAITFBAR: - return 0; - - case BRIG_OPCODE_LDF: - return 1; - - case BRIG_OPCODE_ACTIVELANECOUNT: - case BRIG_OPCODE_ACTIVELANEID: - case BRIG_OPCODE_ACTIVELANEMASK: - case BRIG_OPCODE_ACTIVELANEPERMUTE: - return 1; /* ??? */ - - case BRIG_OPCODE_CALL: - case BRIG_OPCODE_SCALL: - case BRIG_OPCODE_ICALL: - return 0; - - case BRIG_OPCODE_RET: - return 0; - - case BRIG_OPCODE_ALLOCA: - return 1; - - case BRIG_OPCODE_CLEARDETECTEXCEPT: - return 0; - - case BRIG_OPCODE_SETDETECTEXCEPT: - return 0; - - case BRIG_OPCODE_PACKETCOMPLETIONSIG: - case BRIG_OPCODE_PACKETID: - case BRIG_OPCODE_CASQUEUEWRITEINDEX: - case BRIG_OPCODE_LDQUEUEREADINDEX: - case BRIG_OPCODE_LDQUEUEWRITEINDEX: - case BRIG_OPCODE_STQUEUEREADINDEX: - case BRIG_OPCODE_STQUEUEWRITEINDEX: - return 1; /* ??? */ - - case BRIG_OPCODE_ADDQUEUEWRITEINDEX: - return 1; - - case BRIG_OPCODE_DEBUGTRAP: - return 0; - - case BRIG_OPCODE_GROUPBASEPTR: - case BRIG_OPCODE_KERNARGBASEPTR: - return 1; /* ??? */ - - case HSA_OPCODE_ARG_BLOCK: - return 0; - - case BRIG_KIND_DIRECTIVE_COMMENT: - return 0; - } -} - -/* Return the number of source operands for this INSN. */ - -unsigned -hsa_insn_basic::num_used_ops () -{ - gcc_checking_assert (input_count () <= operand_count ()); - - return operand_count () - input_count (); -} - -/* Set alignment to VALUE. */ - -void -hsa_insn_mem::set_align (BrigAlignment8_t value) -{ - /* TODO: Perhaps remove this dump later on: */ - if (dump_file && (dump_flags & TDF_DETAILS) && value < m_align) - { - fprintf (dump_file, "Decreasing alignment to %u in instruction ", value); - dump_hsa_insn (dump_file, this); - } - m_align = value; -} - -/* Return size of HSA type T in bits. */ - -unsigned -hsa_type_bit_size (BrigType16_t t) -{ - switch (t) - { - case BRIG_TYPE_B1: - return 1; - - case BRIG_TYPE_U8: - case BRIG_TYPE_S8: - case BRIG_TYPE_B8: - return 8; - - case BRIG_TYPE_U16: - case BRIG_TYPE_S16: - case BRIG_TYPE_B16: - case BRIG_TYPE_F16: - return 16; - - case BRIG_TYPE_U32: - case BRIG_TYPE_S32: - case BRIG_TYPE_B32: - case BRIG_TYPE_F32: - case BRIG_TYPE_U8X4: - case BRIG_TYPE_U16X2: - case BRIG_TYPE_S8X4: - case BRIG_TYPE_S16X2: - case BRIG_TYPE_F16X2: - return 32; - - case BRIG_TYPE_U64: - case BRIG_TYPE_S64: - case BRIG_TYPE_F64: - case BRIG_TYPE_B64: - case BRIG_TYPE_U8X8: - case BRIG_TYPE_U16X4: - case BRIG_TYPE_U32X2: - case BRIG_TYPE_S8X8: - case BRIG_TYPE_S16X4: - case BRIG_TYPE_S32X2: - case BRIG_TYPE_F16X4: - case BRIG_TYPE_F32X2: - - return 64; - - case BRIG_TYPE_B128: - case BRIG_TYPE_U8X16: - case BRIG_TYPE_U16X8: - case BRIG_TYPE_U32X4: - case BRIG_TYPE_U64X2: - case BRIG_TYPE_S8X16: - case BRIG_TYPE_S16X8: - case BRIG_TYPE_S32X4: - case BRIG_TYPE_S64X2: - case BRIG_TYPE_F16X8: - case BRIG_TYPE_F32X4: - case BRIG_TYPE_F64X2: - return 128; - - default: - gcc_assert (hsa_seen_error ()); - return t; - } -} - -/* Return BRIG bit-type with BITSIZE length. */ - -BrigType16_t -hsa_bittype_for_bitsize (unsigned bitsize) -{ - switch (bitsize) - { - case 1: - return BRIG_TYPE_B1; - case 8: - return BRIG_TYPE_B8; - case 16: - return BRIG_TYPE_B16; - case 32: - return BRIG_TYPE_B32; - case 64: - return BRIG_TYPE_B64; - case 128: - return BRIG_TYPE_B128; - default: - gcc_unreachable (); - } -} - -/* Return BRIG unsigned int type with BITSIZE length. */ - -BrigType16_t -hsa_uint_for_bitsize (unsigned bitsize) -{ - switch (bitsize) - { - case 8: - return BRIG_TYPE_U8; - case 16: - return BRIG_TYPE_U16; - case 32: - return BRIG_TYPE_U32; - case 64: - return BRIG_TYPE_U64; - default: - gcc_unreachable (); - } -} - -/* Return BRIG float type with BITSIZE length. */ - -BrigType16_t -hsa_float_for_bitsize (unsigned bitsize) -{ - switch (bitsize) - { - case 16: - return BRIG_TYPE_F16; - case 32: - return BRIG_TYPE_F32; - case 64: - return BRIG_TYPE_F64; - default: - gcc_unreachable (); - } -} - -/* Return HSA bit-type with the same size as the type T. */ - -BrigType16_t -hsa_bittype_for_type (BrigType16_t t) -{ - return hsa_bittype_for_bitsize (hsa_type_bit_size (t)); -} - -/* Return HSA unsigned integer type with the same size as the type T. */ - -BrigType16_t -hsa_unsigned_type_for_type (BrigType16_t t) -{ - return hsa_uint_for_bitsize (hsa_type_bit_size (t)); -} - -/* Return true if TYPE is a packed HSA type. */ - -bool -hsa_type_packed_p (BrigType16_t type) -{ - return (type & BRIG_TYPE_PACK_MASK) != BRIG_TYPE_PACK_NONE; -} - -/* Return true if and only if TYPE is a floating point number type. */ - -bool -hsa_type_float_p (BrigType16_t type) -{ - switch (type & BRIG_TYPE_BASE_MASK) - { - case BRIG_TYPE_F16: - case BRIG_TYPE_F32: - case BRIG_TYPE_F64: - return true; - default: - return false; - } -} - -/* Return true if and only if TYPE is an integer number type. */ - -bool -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: - case BRIG_TYPE_S8: - case BRIG_TYPE_S16: - case BRIG_TYPE_S32: - case BRIG_TYPE_S64: - return true; - default: - return false; - } -} - -/* Return true if and only if TYPE is an bit-type. */ - -bool -hsa_btype_p (BrigType16_t type) -{ - switch (type & BRIG_TYPE_BASE_MASK) - { - case BRIG_TYPE_B8: - case BRIG_TYPE_B16: - case BRIG_TYPE_B32: - case BRIG_TYPE_B64: - case BRIG_TYPE_B128: - return true; - default: - return false; - } -} - - -/* Return HSA alignment encoding alignment to N bits. */ - -BrigAlignment8_t -hsa_alignment_encoding (unsigned n) -{ - gcc_assert (n >= 8 && !(n & (n - 1))); - if (n >= 256) - return BRIG_ALIGNMENT_32; - - switch (n) - { - case 8: - return BRIG_ALIGNMENT_1; - case 16: - return BRIG_ALIGNMENT_2; - case 32: - return BRIG_ALIGNMENT_4; - case 64: - return BRIG_ALIGNMENT_8; - case 128: - return BRIG_ALIGNMENT_16; - default: - gcc_unreachable (); - } -} - -/* Return HSA alignment encoding alignment of T got - by get_object_alignment. */ - -BrigAlignment8_t -hsa_object_alignment (tree t) -{ - return hsa_alignment_encoding (get_object_alignment (t)); -} - -/* Return byte alignment for given BrigAlignment8_t value. */ - -unsigned -hsa_byte_alignment (BrigAlignment8_t alignment) -{ - gcc_assert (alignment != BRIG_ALIGNMENT_NONE); - - return 1 << (alignment - 1); -} - -/* Return natural alignment of HSA TYPE. */ - -BrigAlignment8_t -hsa_natural_alignment (BrigType16_t type) -{ - return hsa_alignment_encoding (hsa_type_bit_size (type & ~BRIG_TYPE_ARRAY)); -} - -/* Call the correct destructor of a HSA instruction. */ - -void -hsa_destroy_insn (hsa_insn_basic *insn) -{ - if (hsa_insn_phi *phi = dyn_cast (insn)) - phi->~hsa_insn_phi (); - else if (hsa_insn_cbr *br = dyn_cast (insn)) - br->~hsa_insn_cbr (); - else if (hsa_insn_cmp *cmp = dyn_cast (insn)) - cmp->~hsa_insn_cmp (); - else if (hsa_insn_mem *mem = dyn_cast (insn)) - mem->~hsa_insn_mem (); - else if (hsa_insn_atomic *atomic = dyn_cast (insn)) - atomic->~hsa_insn_atomic (); - else if (hsa_insn_seg *seg = dyn_cast (insn)) - seg->~hsa_insn_seg (); - else if (hsa_insn_call *call = dyn_cast (insn)) - call->~hsa_insn_call (); - else if (hsa_insn_arg_block *block = dyn_cast (insn)) - block->~hsa_insn_arg_block (); - else if (hsa_insn_sbr *sbr = dyn_cast (insn)) - sbr->~hsa_insn_sbr (); - else if (hsa_insn_br *br = dyn_cast (insn)) - br->~hsa_insn_br (); - else if (hsa_insn_comment *comment = dyn_cast (insn)) - comment->~hsa_insn_comment (); - else - insn->~hsa_insn_basic (); -} - -/* Call the correct destructor of a HSA operand. */ - -void -hsa_destroy_operand (hsa_op_base *op) -{ - if (hsa_op_code_list *list = dyn_cast (op)) - list->~hsa_op_code_list (); - else if (hsa_op_operand_list *list = dyn_cast (op)) - list->~hsa_op_operand_list (); - else if (hsa_op_reg *reg = dyn_cast (op)) - reg->~hsa_op_reg (); - else if (hsa_op_immed *immed = dyn_cast (op)) - immed->~hsa_op_immed (); - else - op->~hsa_op_base (); -} - -/* Create a mapping between the original function DECL and kernel name NAME. */ - -void -hsa_add_kern_decl_mapping (tree decl, char *name, unsigned omp_data_size, - bool gridified_kernel_p) -{ - hsa_decl_kernel_map_element dkm; - dkm.decl = decl; - dkm.name = name; - dkm.omp_data_size = omp_data_size; - dkm.gridified_kernel_p = gridified_kernel_p; - vec_safe_push (hsa_decl_kernel_mapping, dkm); -} - -/* Return the number of kernel decl name mappings. */ - -unsigned -hsa_get_number_decl_kernel_mappings (void) -{ - return vec_safe_length (hsa_decl_kernel_mapping); -} - -/* Return the decl in the Ith kernel decl name mapping. */ - -tree -hsa_get_decl_kernel_mapping_decl (unsigned i) -{ - return (*hsa_decl_kernel_mapping)[i].decl; -} - -/* Return the name in the Ith kernel decl name mapping. */ - -char * -hsa_get_decl_kernel_mapping_name (unsigned i) -{ - return (*hsa_decl_kernel_mapping)[i].name; -} - -/* Return maximum OMP size for kernel decl name mapping. */ - -unsigned -hsa_get_decl_kernel_mapping_omp_size (unsigned i) -{ - return (*hsa_decl_kernel_mapping)[i].omp_data_size; -} - -/* Return if the function is gridified kernel in decl name mapping. */ - -bool -hsa_get_decl_kernel_mapping_gridified (unsigned i) -{ - return (*hsa_decl_kernel_mapping)[i].gridified_kernel_p; -} - -/* Free the mapping between original decls and kernel names. */ - -void -hsa_free_decl_kernel_mapping (void) -{ - if (hsa_decl_kernel_mapping == NULL) - return; - - for (unsigned i = 0; i < hsa_decl_kernel_mapping->length (); ++i) - free ((*hsa_decl_kernel_mapping)[i].name); - ggc_free (hsa_decl_kernel_mapping); -} - -/* Add new kernel dependency. */ - -void -hsa_add_kernel_dependency (tree caller, const char *called_function) -{ - if (hsa_decl_kernel_dependencies == NULL) - hsa_decl_kernel_dependencies = new hash_map *> (); - - vec *s = NULL; - vec **slot = hsa_decl_kernel_dependencies->get (caller); - if (slot == NULL) - { - s = new vec (); - hsa_decl_kernel_dependencies->put (caller, s); - } - else - s = *slot; - - s->safe_push (called_function); -} - -/* Expansion to HSA needs a few gc roots to hold types, constructors etc. In - order to minimize the number of GTY roots, we'll root them all in the - following array. The individual elements should only be accessed by the - very simple getters (of a pointer-to-tree) below. */ - -static GTY(()) tree hsa_tree_gt_roots[3]; - -tree * -hsa_get_ctor_statements (void) -{ - return &hsa_tree_gt_roots[0]; -} - -tree * -hsa_get_dtor_statements (void) -{ - return &hsa_tree_gt_roots[1]; -} - -tree * -hsa_get_kernel_dispatch_type (void) -{ - return &hsa_tree_gt_roots[2]; -} - -/* Modify the name P in-place so that it is a valid HSA identifier. */ - -void -hsa_sanitize_name (char *p) -{ - for (; *p; p++) - if (*p == '.' || *p == '-') - *p = '_'; -} - -/* Clone the name P, set trailing ampersand and sanitize the name. */ - -char * -hsa_brig_function_name (const char *p) -{ - unsigned len = strlen (p); - char *buf = XNEWVEC (char, len + 2); - - buf[0] = '&'; - buf[len + 1] = '\0'; - memcpy (buf + 1, p, len); - - hsa_sanitize_name (buf); - return buf; -} - -/* Add a flatten attribute and disable vectorization for gpu implementation - function decl GDECL. */ - -void hsa_summary_t::process_gpu_implementation_attributes (tree gdecl) -{ - DECL_ATTRIBUTES (gdecl) - = tree_cons (get_identifier ("flatten"), NULL_TREE, - DECL_ATTRIBUTES (gdecl)); - - tree fn_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (gdecl); - if (fn_opts == NULL_TREE) - fn_opts = optimization_default_node; - fn_opts = copy_node (fn_opts); - TREE_OPTIMIZATION (fn_opts)->x_flag_tree_loop_vectorize = false; - TREE_OPTIMIZATION (fn_opts)->x_flag_tree_slp_vectorize = false; - DECL_FUNCTION_SPECIFIC_OPTIMIZATION (gdecl) = fn_opts; -} - -void -hsa_summary_t::link_functions (cgraph_node *gpu, cgraph_node *host, - hsa_function_kind kind, bool gridified_kernel_p) -{ - hsa_function_summary *gpu_summary = get (gpu); - hsa_function_summary *host_summary = get (host); - - gpu_summary->m_kind = kind; - host_summary->m_kind = kind; - - gpu_summary->m_gpu_implementation_p = true; - host_summary->m_gpu_implementation_p = false; - - gpu_summary->m_gridified_kernel_p = gridified_kernel_p; - host_summary->m_gridified_kernel_p = gridified_kernel_p; - - gpu_summary->m_bound_function = host; - host_summary->m_bound_function = gpu; - - process_gpu_implementation_attributes (gpu->decl); - - /* Create reference between a kernel and a corresponding host implementation - to quarantee LTO streaming to a same LTRANS. */ - if (kind == HSA_KERNEL) - gpu->create_reference (host, IPA_REF_ADDR); -} - -/* Add a HOST function to HSA summaries. */ - -void -hsa_register_kernel (cgraph_node *host) -{ - if (hsa_summaries == NULL) - hsa_summaries = new hsa_summary_t (symtab); - hsa_function_summary *s = hsa_summaries->get (host); - s->m_kind = HSA_KERNEL; -} - -/* Add a pair of functions to HSA summaries. GPU is an HSA implementation of - a HOST function. */ - -void -hsa_register_kernel (cgraph_node *gpu, cgraph_node *host) -{ - if (hsa_summaries == NULL) - hsa_summaries = new hsa_summary_t (symtab); - hsa_summaries->link_functions (gpu, host, HSA_KERNEL, true); -} - -/* Return true if expansion of the current HSA function has already failed. */ - -bool -hsa_seen_error (void) -{ - return hsa_cfun->m_seen_error; -} - -/* Mark current HSA function as failed. */ - -void -hsa_fail_cfun (void) -{ - hsa_failed_functions->add (hsa_cfun->m_decl); - hsa_cfun->m_seen_error = true; -} - -char * -hsa_internal_fn::name () -{ - char *name = xstrdup (internal_fn_name (m_fn)); - for (char *ptr = name; *ptr; ptr++) - *ptr = TOLOWER (*ptr); - - const char *suffix = NULL; - if (m_type_bit_size == 32) - suffix = "f"; - - if (suffix) - { - char *name2 = concat (name, suffix, NULL); - free (name); - name = name2; - } - - hsa_sanitize_name (name); - return name; -} - -unsigned -hsa_internal_fn::get_arity () -{ - switch (m_fn) - { - case IFN_ACOS: - case IFN_ASIN: - case IFN_ATAN: - case IFN_COS: - case IFN_EXP: - case IFN_EXP10: - case IFN_EXP2: - case IFN_EXPM1: - case IFN_LOG: - case IFN_LOG10: - case IFN_LOG1P: - case IFN_LOG2: - case IFN_LOGB: - case IFN_SIGNIFICAND: - case IFN_SIN: - case IFN_SQRT: - case IFN_TAN: - case IFN_CEIL: - case IFN_FLOOR: - case IFN_NEARBYINT: - case IFN_RINT: - case IFN_ROUND: - case IFN_TRUNC: - return 1; - case IFN_ATAN2: - case IFN_COPYSIGN: - case IFN_FMOD: - case IFN_POW: - case IFN_REMAINDER: - case IFN_SCALB: - case IFN_LDEXP: - return 2; - case IFN_CLRSB: - case IFN_CLZ: - case IFN_CTZ: - case IFN_FFS: - case IFN_PARITY: - case IFN_POPCOUNT: - default: - /* As we produce sorry message for unknown internal functions, - reaching this label is definitely a bug. */ - gcc_unreachable (); - } -} - -BrigType16_t -hsa_internal_fn::get_argument_type (int n) -{ - switch (m_fn) - { - case IFN_ACOS: - case IFN_ASIN: - case IFN_ATAN: - case IFN_COS: - case IFN_EXP: - case IFN_EXP10: - case IFN_EXP2: - case IFN_EXPM1: - case IFN_LOG: - case IFN_LOG10: - case IFN_LOG1P: - case IFN_LOG2: - case IFN_LOGB: - case IFN_SIGNIFICAND: - case IFN_SIN: - case IFN_SQRT: - case IFN_TAN: - case IFN_CEIL: - case IFN_FLOOR: - case IFN_NEARBYINT: - case IFN_RINT: - case IFN_ROUND: - case IFN_TRUNC: - case IFN_ATAN2: - case IFN_COPYSIGN: - case IFN_FMOD: - case IFN_POW: - case IFN_REMAINDER: - case IFN_SCALB: - return hsa_float_for_bitsize (m_type_bit_size); - case IFN_LDEXP: - { - if (n == -1 || n == 0) - return hsa_float_for_bitsize (m_type_bit_size); - else - return BRIG_TYPE_S32; - } - default: - /* As we produce sorry message for unknown internal functions, - reaching this label is definitely a bug. */ - gcc_unreachable (); - } -} - -#include "gt-hsa.h" diff --git a/gcc/hsa.h b/gcc/hsa.h deleted file mode 100644 index a74f2d9553b..00000000000 --- a/gcc/hsa.h +++ /dev/null @@ -1,1412 +0,0 @@ -/* HSAIL and BRIG related macros and definitions. - Copyright (C) 2013-2017 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#ifndef HSA_H -#define HSA_H - -#include "hsa-brig-format.h" -#include "is-a.h" -#include "predict.h" -#include "tree.h" -#include "vec.h" -#include "hash-table.h" -#include "basic-block.h" - - -/* Return true if the compiler should produce HSAIL. */ - -static inline bool -hsa_gen_requested_p (void) -{ -#ifndef ENABLE_HSA - return false; -#endif - return !flag_disable_hsa; -} - -/* Standard warning message if we failed to generate HSAIL for a function. */ - -#define HSA_SORRY_MSG "could not emit HSAIL for the function" - -class hsa_op_immed; -class hsa_op_cst_list; -class hsa_insn_basic; -class hsa_op_address; -class hsa_op_reg; -class hsa_bb; - -/* Class representing an input argument, output argument (result) or a - variable, that will eventually end up being a symbol directive. */ - -struct hsa_symbol -{ - /* Constructor. */ - hsa_symbol (BrigType16_t type, BrigSegment8_t segment, - BrigLinkage8_t linkage, bool global_scope_p = false, - BrigAllocation allocation = BRIG_ALLOCATION_AUTOMATIC, - BrigAlignment8_t align = BRIG_ALIGNMENT_8); - - /* Return total size of the symbol. */ - unsigned HOST_WIDE_INT total_byte_size (); - - /* Fill in those values into the symbol according to DECL, which are - determined independently from whether it is parameter, result, - or a variable, local or global. */ - void fillup_for_decl (tree decl); - - /* Pointer to the original tree, which is PARM_DECL for input parameters and - RESULT_DECL for the output parameters. Also can be CONST_DECL for Fortran - constants which need to be put into readonly segment. */ - tree m_decl; - - /* Name of the symbol, that will be written into output and dumps. Can be - NULL, see name_number below. */ - const char *m_name; - - /* If name is NULL, artificial name will be formed from the segment name and - this number. */ - int m_name_number; - - /* Once written, this is the offset of the associated symbol directive. Zero - means the symbol has not been written yet. */ - unsigned m_directive_offset; - - /* HSA type of the parameter. */ - BrigType16_t m_type; - - /* The HSA segment this will eventually end up in. */ - BrigSegment8_t m_segment; - - /* The HSA kind of linkage. */ - BrigLinkage8_t m_linkage; - - /* Array dimension, if non-zero. */ - unsigned HOST_WIDE_INT m_dim; - - /* Constant value, used for string constants. */ - hsa_op_immed *m_cst_value; - - /* Is in global scope. */ - bool m_global_scope_p; - - /* True if an error has been seen for the symbol. */ - bool m_seen_error; - - /* Symbol allocation. */ - BrigAllocation m_allocation; - - /* Flag used for global variables if a variable is already emitted or not. */ - bool m_emitted_to_brig; - - /* Alignment of the symbol. */ - BrigAlignment8_t m_align; - -private: - /* Default constructor. */ - hsa_symbol (); -}; - -/* Abstract class for HSA instruction operands. */ - -class hsa_op_base -{ -public: - /* Next operand scheduled to be written when writing BRIG operand - section. */ - hsa_op_base *m_next; - - /* Offset to which the associated operand structure will be written. Zero if - yet not scheduled for writing. */ - unsigned m_brig_op_offset; - - /* The type of a particular operand. */ - BrigKind16_t m_kind; - -protected: - hsa_op_base (BrigKind16_t k); -private: - /* Make the default constructor inaccessible. */ - hsa_op_base () {} -}; - -/* Common abstract ancestor for operands which have a type. */ - -class hsa_op_with_type : public hsa_op_base -{ -public: - /* The type. */ - BrigType16_t m_type; - - /* Convert an operand to a destination type DTYPE and attach insns - to HBB if needed. */ - hsa_op_with_type *get_in_type (BrigType16_t dtype, hsa_bb *hbb); - -protected: - hsa_op_with_type (BrigKind16_t k, BrigType16_t t); -private: - /* Make the default constructor inaccessible. */ - hsa_op_with_type () : hsa_op_base (BRIG_KIND_NONE) {} -}; - -/* An immediate HSA operand. */ - -class hsa_op_immed : public hsa_op_with_type -{ -public: - hsa_op_immed (tree tree_val, bool min32int = true); - hsa_op_immed (HOST_WIDE_INT int_value, BrigType16_t type); - void *operator new (size_t); - ~hsa_op_immed (); - void set_type (BrigKind16_t t); - - /* Function returns pointer to a buffer that contains binary representation - of the immeadiate value. The buffer has length of BRIG_SIZE and - a caller is responsible for deallocation of the buffer. */ - char *emit_to_buffer (unsigned *brig_size); - - /* Value as represented by middle end. */ - tree m_tree_value; - - /* Integer value representation. */ - HOST_WIDE_INT m_int_value; - -private: - /* Make the default constructor inaccessible. */ - hsa_op_immed (); - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} -}; - -/* Report whether or not P is a an immediate operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_base *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_CONSTANT_BYTES; -} - -/* Likewise, but for a more specified base. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_with_type *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_CONSTANT_BYTES; -} - - -/* HSA register operand. */ - -class hsa_op_reg : public hsa_op_with_type -{ - friend class hsa_insn_basic; - friend class hsa_insn_phi; -public: - hsa_op_reg (BrigType16_t t); - void *operator new (size_t); - - /* Verify register operand. */ - void verify_ssa (); - - /* If NON-NULL, gimple SSA that we come from. NULL if none. */ - tree m_gimple_ssa; - - /* Defining instruction while still in the SSA. */ - hsa_insn_basic *m_def_insn; - - /* If the register allocator decides to spill the register, this is the - appropriate spill symbol. */ - hsa_symbol *m_spill_sym; - - /* Number of this register structure in the order in which they were - allocated. */ - int m_order; - int m_lr_begin, m_lr_end; - - /* Zero if the register is not yet allocated. After, allocation, this must - be 'c', 's', 'd' or 'q'. */ - char m_reg_class; - /* If allocated, the number of the HW register (within its HSA register - class). */ - char m_hard_num; - -private: - /* Make the default constructor inaccessible. */ - hsa_op_reg () : hsa_op_with_type (BRIG_KIND_NONE, BRIG_TYPE_NONE) {} - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} - /* Set definition where the register is defined. */ - void set_definition (hsa_insn_basic *insn); - /* Uses of the value while still in SSA. */ - auto_vec m_uses; -}; - -/* Report whether or not P is a register operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_base *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_REGISTER; -} - -/* Report whether or not P is a register operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_with_type *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_REGISTER; -} - -/* An address HSA operand. */ - -class hsa_op_address : public hsa_op_base -{ -public: - /* set up a new address operand consisting of base symbol SYM, register R and - immediate OFFSET. If the machine model is not large and offset is 64 bit, - the upper, 32 bits have to be zero. */ - hsa_op_address (hsa_symbol *sym, hsa_op_reg *reg, - HOST_WIDE_INT offset = 0); - - void *operator new (size_t); - - /* Set up a new address operand consisting of base symbol SYM and - immediate OFFSET. If the machine model is not large and offset is 64 bit, - the upper, 32 bits have to be zero. */ - hsa_op_address (hsa_symbol *sym, HOST_WIDE_INT offset = 0); - - /* Set up a new address operand consisting of register R and - immediate OFFSET. If the machine model is not large and offset is 64 bit, - the upper, 32 bits have to be zero. */ - hsa_op_address (hsa_op_reg *reg, HOST_WIDE_INT offset = 0); - - /* Symbol base of the address. Can be NULL if there is none. */ - hsa_symbol *m_symbol; - - /* Register offset. Can be NULL if there is none. */ - hsa_op_reg *m_reg; - - /* Immediate byte offset. */ - HOST_WIDE_INT m_imm_offset; - -private: - /* Make the default constructor inaccessible. */ - hsa_op_address () : hsa_op_base (BRIG_KIND_NONE) {} - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} -}; - -/* Report whether or not P is an address operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_base *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_ADDRESS; -} - -/* A reference to code HSA operand. It can be either reference - to a start of a BB or a start of a function. */ - -class hsa_op_code_ref : public hsa_op_base -{ -public: - hsa_op_code_ref (); - - /* Offset in the code section that this refers to. */ - unsigned m_directive_offset; -}; - -/* Report whether or not P is a code reference operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_base *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_CODE_REF; -} - -/* Code list HSA operand. */ - -class hsa_op_code_list: public hsa_op_base -{ -public: - hsa_op_code_list (unsigned elements); - void *operator new (size_t); - - /* Offset to variable-sized array in hsa_data section, where - are offsets to entries in the hsa_code section. */ - auto_vec m_offsets; -private: - /* Make the default constructor inaccessible. */ - hsa_op_code_list () : hsa_op_base (BRIG_KIND_NONE) {} - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} -}; - -/* Report whether or not P is a code list operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_base *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_CODE_LIST; -} - -/* Operand list HSA operand. */ - -class hsa_op_operand_list: public hsa_op_base -{ -public: - hsa_op_operand_list (unsigned elements); - ~hsa_op_operand_list (); - void *operator new (size_t); - - /* Offset to variable-sized array in hsa_data section, where - are offsets to entries in the hsa_code section. */ - auto_vec m_offsets; -private: - /* Make the default constructor inaccessible. */ - hsa_op_operand_list () : hsa_op_base (BRIG_KIND_NONE) {} - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} -}; - -/* Report whether or not P is a code list operand. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_op_base *p) -{ - return p->m_kind == BRIG_KIND_OPERAND_OPERAND_LIST; -} - -/* Opcodes of instructions that are not part of HSA but that we use to - represent it nevertheless. */ - -#define HSA_OPCODE_PHI (-1) -#define HSA_OPCODE_ARG_BLOCK (-2) - -/* The number of operand pointers we can directly in an instruction. */ -#define HSA_BRIG_INT_STORAGE_OPERANDS 5 - -/* Class representing an HSA instruction. Unlike typical ancestors for - specialized classes, this one is also directly used for all instructions - that are then represented as BrigInstBasic. */ - -class hsa_insn_basic -{ -public: - hsa_insn_basic (unsigned nops, int opc); - hsa_insn_basic (unsigned nops, int opc, BrigType16_t t, - hsa_op_base *arg0 = NULL, - hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL, - hsa_op_base *arg3 = NULL); - - void *operator new (size_t); - void set_op (int index, hsa_op_base *op); - hsa_op_base *get_op (int index); - hsa_op_base **get_op_addr (int index); - unsigned int operand_count (); - void verify (); - unsigned input_count (); - unsigned num_used_ops (); - void set_output_in_type (hsa_op_reg *dest, unsigned op_index, hsa_bb *hbb); - bool op_output_p (unsigned opnum); - - /* The previous and next instruction in the basic block. */ - hsa_insn_basic *m_prev, *m_next; - - /* Basic block this instruction belongs to. */ - basic_block m_bb; - - /* Operand code distinguishing different types of instructions. Eventually - these should only be BRIG_INST_* values from the BrigOpcode16_t range but - initially we use negative values for PHI nodes and such. */ - int m_opcode; - - /* Linearized number assigned to the instruction by HSA RA. */ - int m_number; - - /* Type of the destination of the operations. */ - BrigType16_t m_type; - - /* BRIG offset of the instruction in code section. */ - unsigned int m_brig_offset; - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_basic () {} - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} - /* The individual operands. All instructions but PHI nodes have five or - fewer instructions and so will fit the internal storage. */ - /* TODO: Vast majority of instructions have three or fewer operands, so we - may actually try reducing it. */ - auto_vec m_operands; -}; - -/* Class representing a PHI node of the SSA form of HSA virtual - registers. */ - -class hsa_insn_phi : public hsa_insn_basic -{ -public: - hsa_insn_phi (unsigned nops, hsa_op_reg *dst); - - /* Destination. */ - hsa_op_reg *m_dest; - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_phi () : hsa_insn_basic (1, HSA_OPCODE_PHI) {} -}; - -/* Report whether or not P is a PHI node. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return p->m_opcode == HSA_OPCODE_PHI; -} - -/* HSA instruction for */ -class hsa_insn_br : public hsa_insn_basic -{ -public: - hsa_insn_br (unsigned nops, int opc, BrigType16_t t, BrigWidth8_t width, - hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); - - /* Number of work-items affected in the same way by the instruction. */ - BrigWidth8_t m_width; - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_br () : hsa_insn_basic (0, BRIG_OPCODE_BR) {} -}; - -/* Return true if P is a branching/synchronization instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return p->m_opcode == BRIG_OPCODE_BARRIER - || p->m_opcode == BRIG_OPCODE_BR; -} - -/* HSA instruction for conditional branches. Structurally the same as - hsa_insn_br but we represent it specially because of inherent control - flow it represents. */ - -class hsa_insn_cbr : public hsa_insn_br -{ -public: - hsa_insn_cbr (hsa_op_reg *ctrl); - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_cbr () : hsa_insn_br (0, BRIG_OPCODE_CBR, BRIG_TYPE_B1, - BRIG_WIDTH_1) {} -}; - -/* Report whether P is a contitional branching instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return p->m_opcode == BRIG_OPCODE_CBR; -} - -/* HSA instruction for switch branches. */ - -class hsa_insn_sbr : public hsa_insn_basic -{ -public: - hsa_insn_sbr (hsa_op_reg *index, unsigned jump_count); - - /* Default destructor. */ - ~hsa_insn_sbr (); - - void replace_all_labels (basic_block old_bb, basic_block new_bb); - - /* Width as described in HSA documentation. */ - BrigWidth8_t m_width; - - /* Jump table. */ - vec m_jump_table; - - /* Code list for label references. */ - hsa_op_code_list *m_label_code_list; - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_sbr () : hsa_insn_basic (1, BRIG_OPCODE_SBR) {} -}; - -/* Report whether P is a switch branching instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return p->m_opcode == BRIG_OPCODE_SBR; -} - -/* HSA instruction for comparisons. */ - -class hsa_insn_cmp : public hsa_insn_basic -{ -public: - hsa_insn_cmp (BrigCompareOperation8_t cmp, BrigType16_t t, - hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL); - - /* Source type should be derived from operand types. */ - - /* The comparison operation. */ - BrigCompareOperation8_t m_compare; - - /* TODO: Modifiers and packing control are missing but so are everywhere - else. */ -private: - /* Make the default constructor inaccessible. */ - hsa_insn_cmp () : hsa_insn_basic (1, BRIG_OPCODE_CMP) {} -}; - -/* Report whether or not P is a comparison instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return p->m_opcode == BRIG_OPCODE_CMP; -} - -/* HSA instruction for memory operations. */ - -class hsa_insn_mem : public hsa_insn_basic -{ -public: - hsa_insn_mem (int opc, BrigType16_t t, hsa_op_base *arg0, hsa_op_base *arg1); - - /* Set alignment to VALUE. */ - - void set_align (BrigAlignment8_t value); - - /* The segment is of the memory access is either the segment of the symbol in - the address operand or flat address is there is no symbol there. */ - - /* Required alignment of the memory operation. */ - BrigAlignment8_t m_align; - - /* HSA equiv class, basically an alias set number. */ - uint8_t m_equiv_class; - - /* TODO: Add width modifier, perhaps also other things. */ -protected: - hsa_insn_mem (unsigned nops, int opc, BrigType16_t t, - hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_mem () : hsa_insn_basic (1, BRIG_OPCODE_LD) {} -}; - -/* Report whether or not P is a memory instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_LD - || p->m_opcode == BRIG_OPCODE_ST); -} - -/* HSA instruction for atomic operations. */ - -class hsa_insn_atomic : public hsa_insn_mem -{ -public: - hsa_insn_atomic (int nops, int opc, enum BrigAtomicOperation aop, - BrigType16_t t, BrigMemoryOrder memorder, - hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); - - /* The operation itself. */ - enum BrigAtomicOperation m_atomicop; - - /* Things like acquire/release/aligned. */ - enum BrigMemoryOrder m_memoryorder; - - /* Scope of the atomic operation. */ - enum BrigMemoryScope m_memoryscope; - -private: - /* Make the default constructor inaccessible. */ - hsa_insn_atomic () : hsa_insn_mem (1, BRIG_KIND_NONE, BRIG_TYPE_NONE) {} -}; - -/* Report whether or not P is an atomic instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_ATOMIC - || p->m_opcode == BRIG_OPCODE_ATOMICNORET); -} - -/* HSA instruction for signal operations. */ - -class hsa_insn_signal : public hsa_insn_basic -{ -public: - hsa_insn_signal (int nops, int opc, enum BrigAtomicOperation sop, - BrigType16_t t, BrigMemoryOrder memorder, - hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); - - /* Things like acquire/release/aligned. */ - enum BrigMemoryOrder m_memory_order; - - /* The operation itself. */ - enum BrigAtomicOperation m_signalop; -}; - -/* Report whether or not P is a signal instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_SIGNAL - || p->m_opcode == BRIG_OPCODE_SIGNALNORET); -} - -/* HSA instruction to convert between flat addressing and segments. */ - -class hsa_insn_seg : public hsa_insn_basic -{ -public: - hsa_insn_seg (int opc, BrigType16_t destt, BrigType16_t srct, - BrigSegment8_t seg, hsa_op_base *arg0, hsa_op_base *arg1); - - /* Source type. Depends on the source addressing/segment. */ - BrigType16_t m_src_type; - /* The segment we are converting from or to. */ - BrigSegment8_t m_segment; -private: - /* Make the default constructor inaccessible. */ - hsa_insn_seg () : hsa_insn_basic (1, BRIG_OPCODE_STOF) {} -}; - -/* Report whether or not P is a segment conversion instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_STOF - || p->m_opcode == BRIG_OPCODE_FTOS); -} - -/* Class for internal functions for purpose of HSA emission. */ - -class hsa_internal_fn -{ -public: - hsa_internal_fn (enum internal_fn fn, unsigned type_bit_size): - m_fn (fn), m_type_bit_size (type_bit_size), m_offset (0) {} - - hsa_internal_fn (const hsa_internal_fn *f): - m_fn (f->m_fn), m_type_bit_size (f->m_type_bit_size), - m_offset (f->m_offset) {} - - /* Return arity of the internal function. */ - unsigned get_arity (); - - /* Return BRIG type of N-th argument, if -1 is passed, return value type - is received. */ - BrigType16_t get_argument_type (int n); - - /* Return function name. The memory must be released by a caller. */ - char *name (); - - /* Internal function. */ - enum internal_fn m_fn; - - /* Bit width of return type. */ - unsigned m_type_bit_size; - - /* BRIG offset of declaration of the function. */ - BrigCodeOffset32_t m_offset; -}; - -/* HSA instruction for function call. */ - -class hsa_insn_call : public hsa_insn_basic -{ -public: - hsa_insn_call (tree callee); - hsa_insn_call (hsa_internal_fn *fn); - - /* Default destructor. */ - ~hsa_insn_call (); - - /* Called function. */ - tree m_called_function; - - /* Called internal function. */ - hsa_internal_fn *m_called_internal_fn; - - /* Input formal arguments. */ - auto_vec m_input_args; - - /* Input arguments store instructions. */ - auto_vec m_input_arg_insns; - - /* Output argument, can be NULL for void functions. */ - hsa_symbol *m_output_arg; - - /* Called function code reference. */ - hsa_op_code_ref m_func; - - /* Code list for arguments of the function. */ - hsa_op_code_list *m_args_code_list; - - /* Code list for result of the function. */ - hsa_op_code_list *m_result_code_list; -private: - /* Make the default constructor inaccessible. */ - hsa_insn_call () : hsa_insn_basic (0, BRIG_OPCODE_CALL) {} -}; - -/* Report whether or not P is a call instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_CALL); -} - -/* HSA call instruction block encapsulates definition of arguments, - result type, corresponding loads and a possible store. - Moreover, it contains a single call instruction. - Emission of the instruction will produce multiple - HSAIL instructions. */ - -class hsa_insn_arg_block : public hsa_insn_basic -{ -public: - hsa_insn_arg_block (BrigKind brig_kind, hsa_insn_call * call); - - /* Kind of argument block. */ - BrigKind m_kind; - - /* Call instruction. */ - hsa_insn_call *m_call_insn; -}; - -/* Report whether or not P is a call block instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == HSA_OPCODE_ARG_BLOCK); -} - -/* HSA comment instruction. */ - -class hsa_insn_comment: public hsa_insn_basic -{ -public: - /* Constructor of class representing the comment in HSAIL. */ - hsa_insn_comment (const char *s); - - /* Default destructor. */ - ~hsa_insn_comment (); - - char *m_comment; -}; - -/* Report whether or not P is a call block instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_KIND_DIRECTIVE_COMMENT); -} - -/* HSA queue instruction. */ - -class hsa_insn_queue: public hsa_insn_basic -{ -public: - hsa_insn_queue (int nops, int opcode, BrigSegment segment, - BrigMemoryOrder memory_order, - hsa_op_base *arg0 = NULL, hsa_op_base *arg1 = NULL, - hsa_op_base *arg2 = NULL, hsa_op_base *arg3 = NULL); - - /* Destructor. */ - ~hsa_insn_queue (); - - /* Segment used to refer to the queue. Must be global or flat. */ - BrigSegment m_segment; - /* Memory order used to specify synchronization. */ - BrigMemoryOrder m_memory_order; -}; - -/* Report whether or not P is a queue instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_ADDQUEUEWRITEINDEX - || p->m_opcode == BRIG_OPCODE_CASQUEUEWRITEINDEX - || p->m_opcode == BRIG_OPCODE_LDQUEUEREADINDEX - || p->m_opcode == BRIG_OPCODE_LDQUEUEWRITEINDEX - || p->m_opcode == BRIG_OPCODE_STQUEUEREADINDEX - || p->m_opcode == BRIG_OPCODE_STQUEUEWRITEINDEX); -} - -/* HSA source type instruction. */ - -class hsa_insn_srctype: public hsa_insn_basic -{ -public: - hsa_insn_srctype (int nops, BrigOpcode opcode, BrigType16_t destt, - BrigType16_t srct, hsa_op_base *arg0, hsa_op_base *arg1, - hsa_op_base *arg2); - - /* Source type. */ - BrigType16_t m_source_type; - - /* Destructor. */ - ~hsa_insn_srctype (); -}; - -/* Report whether or not P is a source type instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_POPCOUNT - || p->m_opcode == BRIG_OPCODE_FIRSTBIT - || p->m_opcode == BRIG_OPCODE_LASTBIT); -} - -/* HSA packed instruction. */ - -class hsa_insn_packed : public hsa_insn_srctype -{ -public: - hsa_insn_packed (int nops, BrigOpcode opcode, BrigType16_t destt, - BrigType16_t srct, hsa_op_base *arg0, hsa_op_base *arg1, - hsa_op_base *arg2); - - /* Operand list for an operand of the instruction. */ - hsa_op_operand_list *m_operand_list; - - /* Destructor. */ - ~hsa_insn_packed (); -}; - -/* Report whether or not P is a combine instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_COMBINE - || p->m_opcode == BRIG_OPCODE_EXPAND); -} - -/* HSA convert instruction. */ - -class hsa_insn_cvt: public hsa_insn_basic -{ -public: - hsa_insn_cvt (hsa_op_with_type *dest, hsa_op_with_type *src); -}; - -/* Report whether or not P is a convert instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_CVT); -} - -/* HSA alloca instruction. */ - -class hsa_insn_alloca: public hsa_insn_basic -{ -public: - hsa_insn_alloca (hsa_op_with_type *dest, hsa_op_with_type *size, - unsigned alignment = 0); - - /* Required alignment of the allocation. */ - BrigAlignment8_t m_align; -}; - -/* Report whether or not P is an alloca instruction. */ - -template <> -template <> -inline bool -is_a_helper ::test (hsa_insn_basic *p) -{ - return (p->m_opcode == BRIG_OPCODE_ALLOCA); -} - -/* Basic block of HSA instructions. */ - -class hsa_bb -{ -public: - hsa_bb (basic_block cfg_bb); - hsa_bb (basic_block cfg_bb, int idx); - ~hsa_bb (); - - /* Append an instruction INSN into the basic block. */ - void append_insn (hsa_insn_basic *insn); - - /* Add a PHI instruction. */ - void append_phi (hsa_insn_phi *phi); - - /* The real CFG BB that this HBB belongs to. */ - basic_block m_bb; - - /* The operand that refers to the label to this BB. */ - hsa_op_code_ref m_label_ref; - - /* The first and last instruction. */ - hsa_insn_basic *m_first_insn, *m_last_insn; - /* The first and last phi node. */ - hsa_insn_phi *m_first_phi, *m_last_phi; - - /* Just a number to construct names from. */ - int m_index; - - bitmap m_liveout, m_livein; -private: - /* Make the default constructor inaccessible. */ - hsa_bb (); - /* All objects are deallocated by destroying their pool, so make delete - inaccessible too. */ - void operator delete (void *) {} -}; - -/* Return the corresponding HSA basic block structure for the given control - flow basic_block BB. */ - -static inline hsa_bb * -hsa_bb_for_bb (basic_block bb) -{ - return (struct hsa_bb *) bb->aux; -} - -/* Class for hashing local hsa_symbols. */ - -struct hsa_noop_symbol_hasher : nofree_ptr_hash -{ - static inline hashval_t hash (const value_type); - static inline bool equal (const value_type, const compare_type); -}; - -/* Hash hsa_symbol. */ - -inline hashval_t -hsa_noop_symbol_hasher::hash (const value_type item) -{ - return DECL_UID (item->m_decl); -} - -/* Return true if the DECL_UIDs of decls both symbols refer to are equal. */ - -inline bool -hsa_noop_symbol_hasher::equal (const value_type a, const compare_type b) -{ - return (DECL_UID (a->m_decl) == DECL_UID (b->m_decl)); -} - -/* Structure that encapsulates intermediate representation of a HSA - function. */ - -class hsa_function_representation -{ -public: - hsa_function_representation (tree fdecl, bool kernel_p, - unsigned ssa_names_count, - bool modified_cfg = false); - hsa_function_representation (hsa_internal_fn *fn); - ~hsa_function_representation (); - - /* Builds a shadow register that is utilized to a kernel dispatch. */ - hsa_op_reg *get_shadow_reg (); - - /* Return true if we are in a function that has kernel dispatch - shadow register. */ - bool has_shadow_reg_p (); - - /* The entry/exit blocks don't contain incoming code, - but the HSA generator might use them to put code into, - so we need hsa_bb instances of them. */ - void init_extra_bbs (); - - /* Update CFG dominators if m_modified_cfg flag is set. */ - void update_dominance (); - - /* Return linkage of the representation. */ - BrigLinkage8_t get_linkage (); - - /* Create a private symbol of requested TYPE. */ - hsa_symbol *create_hsa_temporary (BrigType16_t type); - - /* Lookup or create a HSA pseudo register for a given gimple SSA name. */ - hsa_op_reg *reg_for_gimple_ssa (tree ssa); - - /* Name of the function. */ - char *m_name; - - /* Number of allocated register structures. */ - int m_reg_count; - - /* Input arguments. */ - vec m_input_args; - - /* Output argument or NULL if there is none. */ - hsa_symbol *m_output_arg; - - /* Hash table of local variable symbols. */ - hash_table *m_local_symbols; - - /* Hash map for string constants. */ - hash_map m_string_constants_map; - - /* Vector of pointers to spill symbols. */ - vec m_spill_symbols; - - /* Vector of pointers to global variables and transformed string constants - that are used by the function. */ - vec m_global_symbols; - - /* Private function artificial variables. */ - vec m_private_variables; - - /* Vector of called function declarations. */ - vec m_called_functions; - - /* Vector of used internal functions. */ - vec m_called_internal_fns; - - /* Number of HBB BBs. */ - int m_hbb_count; - - /* Whether or not we could check and enforce SSA properties. */ - bool m_in_ssa; - - /* True if the function is kernel function. */ - bool m_kern_p; - - /* True if the function representation is a declaration. */ - bool m_declaration_p; - - /* Function declaration tree. */ - tree m_decl; - - /* Internal function info is used for declarations of internal functions. */ - hsa_internal_fn *m_internal_fn; - - /* Runtime shadow register. */ - hsa_op_reg *m_shadow_reg; - - /* Number of kernel dispatched which take place in the function. */ - unsigned m_kernel_dispatch_count; - - /* If the function representation contains a kernel dispatch, - OMP data size is necessary memory that is used for copying before - a kernel dispatch. */ - unsigned m_maximum_omp_data_size; - - /* Return true if there's an HSA-specific warning already seen. */ - bool m_seen_error; - - /* Counter for temporary symbols created in the function representation. */ - unsigned m_temp_symbol_count; - - /* SSA names mapping. */ - vec m_ssa_map; - - /* Flag whether a function needs update of dominators before RA. */ - bool m_modified_cfg; -}; - -enum hsa_function_kind -{ - HSA_NONE, - HSA_KERNEL, - HSA_FUNCTION -}; - -struct hsa_function_summary -{ - /* Default constructor. */ - hsa_function_summary (); - - /* Kind of GPU/host function. */ - hsa_function_kind m_kind; - - /* Pointer to a cgraph node which is a HSA implementation of the function. - In case of the function is a HSA function, the bound function points - to the host function. */ - cgraph_node *m_bound_function; - - /* Identifies if the function is an HSA function or a host function. */ - bool m_gpu_implementation_p; - - /* True if the function is a gridified kernel. */ - bool m_gridified_kernel_p; -}; - -inline -hsa_function_summary::hsa_function_summary (): m_kind (HSA_NONE), - m_bound_function (NULL), m_gpu_implementation_p (false) -{ -} - -/* Function summary for HSA functions. */ -class hsa_summary_t: public function_summary -{ -public: - hsa_summary_t (symbol_table *table): - function_summary (table) { } - - /* Couple GPU and HOST as gpu-specific and host-specific implementation of - the same function. KIND determines whether GPU is a host-invokable kernel - or gpu-callable function and GRIDIFIED_KERNEL_P is set if the function was - gridified in OMP. */ - - void link_functions (cgraph_node *gpu, cgraph_node *host, - hsa_function_kind kind, bool gridified_kernel_p); - -private: - void process_gpu_implementation_attributes (tree gdecl); -}; - -/* OMP simple builtin describes behavior that should be done for - the routine. */ -class omp_simple_builtin -{ -public: - omp_simple_builtin (const char *name, const char *warning_message, - bool sorry, hsa_op_immed *return_value = NULL): - m_name (name), m_warning_message (warning_message), m_sorry (sorry), - m_return_value (return_value) - {} - - /* Generate HSAIL instructions for the builtin or produce warning message. */ - void generate (gimple *stmt, hsa_bb *hbb); - - /* Name of function. */ - const char *m_name; - - /* Warning message. */ - const char *m_warning_message; - - /* Flag if we should sorry after the warning message is printed. */ - bool m_sorry; - - /* Return value of the function. */ - hsa_op_immed *m_return_value; - - /* Emission function. */ - void (*m_emit_func) (gimple *stmt, hsa_bb *); -}; - -/* Class for hashing hsa_internal_fn. */ - -struct hsa_internal_fn_hasher: free_ptr_hash -{ - static inline hashval_t hash (const value_type); - static inline bool equal (const value_type, const compare_type); -}; - -/* Hash hsa_symbol. */ - -inline hashval_t -hsa_internal_fn_hasher::hash (const value_type item) -{ - return item->m_fn; -} - -/* Return true if the DECL_UIDs of decls both symbols refer to are equal. */ - -inline bool -hsa_internal_fn_hasher::equal (const value_type a, const compare_type b) -{ - return a->m_fn == b->m_fn && a->m_type_bit_size == b->m_type_bit_size; -} - -/* in hsa.c */ -extern struct hsa_function_representation *hsa_cfun; -extern hash_map *> *hsa_decl_kernel_dependencies; -extern hsa_summary_t *hsa_summaries; -extern hsa_symbol *hsa_num_threads; -extern unsigned hsa_kernel_calls_counter; -extern hash_set *hsa_failed_functions; -extern hash_table *hsa_global_variable_symbols; - -bool hsa_callable_function_p (tree fndecl); -void hsa_init_compilation_unit_data (void); -void hsa_deinit_compilation_unit_data (void); -bool hsa_machine_large_p (void); -bool hsa_full_profile_p (void); -bool hsa_opcode_floating_bit_insn_p (BrigOpcode16_t); -unsigned hsa_type_bit_size (BrigType16_t t); -BrigType16_t hsa_bittype_for_bitsize (unsigned bitsize); -BrigType16_t hsa_uint_for_bitsize (unsigned bitsize); -BrigType16_t hsa_float_for_bitsize (unsigned bitsize); -BrigType16_t hsa_bittype_for_type (BrigType16_t t); -BrigType16_t hsa_unsigned_type_for_type (BrigType16_t t); -bool hsa_type_packed_p (BrigType16_t type); -bool hsa_type_float_p (BrigType16_t type); -bool hsa_type_integer_p (BrigType16_t type); -bool hsa_btype_p (BrigType16_t type); -BrigAlignment8_t hsa_alignment_encoding (unsigned n); -BrigAlignment8_t hsa_natural_alignment (BrigType16_t type); -BrigAlignment8_t hsa_object_alignment (tree t); -unsigned hsa_byte_alignment (BrigAlignment8_t alignment); -void hsa_destroy_operand (hsa_op_base *op); -void hsa_destroy_insn (hsa_insn_basic *insn); -void hsa_add_kern_decl_mapping (tree decl, char *name, unsigned, bool); -unsigned hsa_get_number_decl_kernel_mappings (void); -tree hsa_get_decl_kernel_mapping_decl (unsigned i); -char *hsa_get_decl_kernel_mapping_name (unsigned i); -unsigned hsa_get_decl_kernel_mapping_omp_size (unsigned i); -bool hsa_get_decl_kernel_mapping_gridified (unsigned i); -void hsa_free_decl_kernel_mapping (void); -tree *hsa_get_ctor_statements (void); -tree *hsa_get_dtor_statements (void); -tree *hsa_get_kernel_dispatch_type (void); -void hsa_add_kernel_dependency (tree caller, const char *called_function); -void hsa_sanitize_name (char *p); -char *hsa_brig_function_name (const char *p); -const char *hsa_get_declaration_name (tree decl); -void hsa_register_kernel (cgraph_node *host); -void hsa_register_kernel (cgraph_node *gpu, cgraph_node *host); -bool hsa_seen_error (void); -void hsa_fail_cfun (void); - -/* In hsa-gen.c. */ -void hsa_build_append_simple_mov (hsa_op_reg *, hsa_op_base *, hsa_bb *); -hsa_symbol *hsa_get_spill_symbol (BrigType16_t); -hsa_symbol *hsa_get_string_cst_symbol (BrigType16_t); -hsa_op_reg *hsa_spill_in (hsa_insn_basic *, hsa_op_reg *, hsa_op_reg **); -hsa_op_reg *hsa_spill_out (hsa_insn_basic *, hsa_op_reg *, hsa_op_reg **); -hsa_bb *hsa_init_new_bb (basic_block); -hsa_function_representation *hsa_generate_function_declaration (tree decl); -hsa_function_representation *hsa_generate_internal_fn_decl (hsa_internal_fn *); -tree hsa_get_host_function (tree decl); - -/* In hsa-regalloc.c. */ -void hsa_regalloc (void); - -/* In hsa-brig.c. */ -extern hash_table *hsa_emitted_internal_decls; -void hsa_brig_emit_function (void); -void hsa_output_brig (void); -unsigned hsa_get_imm_brig_type_len (BrigType16_t type); -void hsa_brig_emit_omp_symbols (void); - -/* In hsa-dump.c. */ -const char *hsa_seg_name (BrigSegment8_t); -void dump_hsa_insn (FILE *f, hsa_insn_basic *insn); -void dump_hsa_bb (FILE *, hsa_bb *); -void dump_hsa_cfun (FILE *); -DEBUG_FUNCTION void debug_hsa_operand (hsa_op_base *opc); -DEBUG_FUNCTION void debug_hsa_insn (hsa_insn_basic *insn); - -union hsa_bytes -{ - uint8_t b8; - uint16_t b16; - uint32_t b32; - uint64_t b64; -}; - -/* Return true if a function DECL is an HSA implementation. */ - -static inline bool -hsa_gpu_implementation_p (tree decl) -{ - if (hsa_summaries == NULL) - return false; - - hsa_function_summary *s = hsa_summaries->get (cgraph_node::get_create (decl)); - - return s->m_gpu_implementation_p; -} - -#endif /* HSA_H */ diff --git a/gcc/ipa-hsa.c b/gcc/ipa-hsa.c index 6a3f660672e..af70b0a9230 100644 --- a/gcc/ipa-hsa.c +++ b/gcc/ipa-hsa.c @@ -41,7 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "print-tree.h" #include "symbol-summary.h" -#include "hsa.h" +#include "hsa-common.h" namespace { diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index f0e98873e28..57d9fdea85a 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -56,7 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "cilk.h" #include "gomp-constants.h" #include "gimple-pretty-print.h" -#include "hsa.h" +#include "hsa-common.h" /* OMP region information. Every parallel and workshare diff --git a/gcc/omp-low.c b/gcc/omp-low.c index e8d78a91abc..6d30ca617b3 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -57,7 +57,7 @@ along with GCC; see the file COPYING3. If not see #include "context.h" #include "gomp-constants.h" #include "gimple-pretty-print.h" -#include "hsa.h" +#include "hsa-common.h" /* Lowering of OMP parallel and workshare constructs proceeds in two phases. The first phase scans the function looking for OMP statements diff --git a/gcc/toplev.c b/gcc/toplev.c index c0f1a2df517..2335ad716ae 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -77,7 +77,7 @@ along with GCC; see the file COPYING3. If not see #include "gcse.h" #include "tree-chkp.h" #include "omp-offload.h" -#include "hsa.h" +#include "hsa-common.h" #include "edit-context.h" #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)