| /* Implementation of commonly needed HSAIL related functions and methods. |
| Copyright (C) 2013-2019 Free Software Foundation, Inc. |
| Contributed by Martin Jambor <mjambor@suse.cz> and |
| Martin Liska <mliska@suse.cz>. |
| |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| #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" |
| #include "stringpool.h" |
| #include "attribs.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_map_element, va_gc> |
| *hsa_decl_kernel_mapping; |
| |
| /* Mapping between decls and corresponding HSA kernels |
| called by the function. */ |
| hash_map <tree, vec <const char *> *> *hsa_decl_kernel_dependencies; |
| |
| /* Hash function to lookup a symbol for a decl. */ |
| hash_table <hsa_noop_symbol_hasher> *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 <tree> *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 <hsa_noop_symbol_hasher> (8); |
| hsa_failed_functions = new hash_set <tree> (); |
| hsa_emitted_internal_decls = new hash_table <hsa_internal_fn_hasher> (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 <hsa_noop_symbol_hasher>::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 <hsa_insn_phi *> (insn)) |
| phi->~hsa_insn_phi (); |
| else if (hsa_insn_cbr *br = dyn_cast <hsa_insn_cbr *> (insn)) |
| br->~hsa_insn_cbr (); |
| else if (hsa_insn_cmp *cmp = dyn_cast <hsa_insn_cmp *> (insn)) |
| cmp->~hsa_insn_cmp (); |
| else if (hsa_insn_mem *mem = dyn_cast <hsa_insn_mem *> (insn)) |
| mem->~hsa_insn_mem (); |
| else if (hsa_insn_atomic *atomic = dyn_cast <hsa_insn_atomic *> (insn)) |
| atomic->~hsa_insn_atomic (); |
| else if (hsa_insn_seg *seg = dyn_cast <hsa_insn_seg *> (insn)) |
| seg->~hsa_insn_seg (); |
| else if (hsa_insn_call *call = dyn_cast <hsa_insn_call *> (insn)) |
| call->~hsa_insn_call (); |
| else if (hsa_insn_arg_block *block = dyn_cast <hsa_insn_arg_block *> (insn)) |
| block->~hsa_insn_arg_block (); |
| else if (hsa_insn_sbr *sbr = dyn_cast <hsa_insn_sbr *> (insn)) |
| sbr->~hsa_insn_sbr (); |
| else if (hsa_insn_br *br = dyn_cast <hsa_insn_br *> (insn)) |
| br->~hsa_insn_br (); |
| else if (hsa_insn_comment *comment = dyn_cast <hsa_insn_comment *> (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 <hsa_op_code_list *> (op)) |
| list->~hsa_op_code_list (); |
| else if (hsa_op_operand_list *list = dyn_cast <hsa_op_operand_list *> (op)) |
| list->~hsa_op_operand_list (); |
| else if (hsa_op_reg *reg = dyn_cast <hsa_op_reg *> (op)) |
| reg->~hsa_op_reg (); |
| else if (hsa_op_immed *immed = dyn_cast <hsa_op_immed *> (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<tree, vec<const char *> *> (); |
| |
| vec <const char *> *s = NULL; |
| vec <const char *> **slot = hsa_decl_kernel_dependencies->get (caller); |
| if (slot == NULL) |
| { |
| s = new vec <const char *> (); |
| 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_create (gpu); |
| hsa_function_summary *host_summary = get_create (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_create (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" |