From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2093) id 231F53857404; Fri, 21 Oct 2022 04:21:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 231F53857404 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1666326084; bh=/vwJ2vtY1amBM2LWCJyhVILUw0p9zg13UYDFq0oRDSY=; h=From:To:Subject:Date:From; b=hIWjwcMidgaVbGMB4gzPcIKIZiXaUenfwuvLOVWIhSGEo2vTZ95ufLnxhQqlCRZRh 4VRk633IIlsGFuG8Y9xS1NHb15NWdhpHtE6afqgWYHUmw2MJjdlyj0tGM2vXXfVdbj Hxsoj/JujYw44kG8oCbjdV7XJQ3s7hEAi/Ys33AE= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Kito Cheng To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-3426] RISC-V: Add RVV intrinsic basic framework. X-Act-Checkin: gcc X-Git-Author: Ju-Zhe Zhong X-Git-Refname: refs/heads/master X-Git-Oldrev: 4e7ec7dbbbef3b4a83da5967b5f25e3be90c2dc6 X-Git-Newrev: cbd505700e09cfea8bdaa93ad6bd0514372e9034 Message-Id: <20221021042124.231F53857404@sourceware.org> Date: Fri, 21 Oct 2022 04:21:24 +0000 (GMT) List-Id: https://gcc.gnu.org/g:cbd505700e09cfea8bdaa93ad6bd0514372e9034 commit r13-3426-gcbd505700e09cfea8bdaa93ad6bd0514372e9034 Author: Ju-Zhe Zhong Date: Mon Oct 17 16:20:43 2022 +0800 RISC-V: Add RVV intrinsic basic framework. gcc/ChangeLog: * config.gcc: Add gt files since function_instance is GTY ((user)). * config/riscv/riscv-builtins.cc (riscv_init_builtins): Add RVV intrinsic framework. (riscv_builtin_decl): Ditto. (riscv_expand_builtin): Ditto. * config/riscv/riscv-protos.h (builtin_decl): New function. (expand_builtin): Ditto. (enum riscv_builtin_class): New enum to classify RVV intrinsic and RISC-V general built-in. * config/riscv/riscv-vector-builtins.cc (class GTY): New declaration. (struct registered_function_hasher): New struct. (DEF_RVV_OP_TYPE): New macro. (DEF_RVV_TYPE): Ditto. (DEF_RVV_PRED_TYPE): Ditto. (GTY): New declaration. (add_attribute): New function. (check_required_extensions): Ditto. (rvv_arg_type_info::get_tree_type): Ditto. (function_instance::function_instance): Ditto. (function_instance::operator==): Ditto. (function_instance::any_type_float_p): Ditto. (function_instance::get_return_type): Ditto. (function_instance::get_arg_type): Ditto. (function_instance::hash): Ditto. (function_instance::call_properties): Ditto. (function_instance::reads_global_state_p): Ditto. (function_instance::modifies_global_state_p): Ditto. (function_instance::could_trap_p): Ditto. (function_builder::function_builder): Ditto. (function_builder::~function_builder): Ditto. (function_builder::allocate_argument_types): Ditto. (function_builder::register_function_group): Ditto. (function_builder::append_name): Ditto. (function_builder::finish_name): Ditto. (function_builder::get_attributes): Ditto. (function_builder::add_function): Ditto. (function_builder::add_unique_function): Ditto. (function_call_info::function_call_info): Ditto. (function_expander::function_expander): Ditto. (function_expander::add_input_operand): Ditto. (function_expander::generate_insn): Ditto. (registered_function_hasher::hash): Ditto. (registered_function_hasher::equal): Ditto. (builtin_decl): Ditto. (expand_builtin): Ditto. (gt_ggc_mx): Define for using GCC garbage collect. (gt_pch_nx): Define for using GCC garbage collect. * config/riscv/riscv-vector-builtins.def (DEF_RVV_OP_TYPE): New macro. (DEF_RVV_PRED_TYPE): Ditto. (vbool64_t): Add suffix. (vbool32_t): Ditto. (vbool16_t): Ditto. (vbool8_t): Ditto. (vbool4_t): Ditto. (vbool2_t): Ditto. (vbool1_t): Ditto. (vint8mf8_t): Ditto. (vuint8mf8_t): Ditto. (vint8mf4_t): Ditto. (vuint8mf4_t): Ditto. (vint8mf2_t): Ditto. (vuint8mf2_t): Ditto. (vint8m1_t): Ditto. (vuint8m1_t): Ditto. (vint8m2_t): Ditto. (vuint8m2_t): Ditto. (vint8m4_t): Ditto. (vuint8m4_t): Ditto. (vint8m8_t): Ditto. (vuint8m8_t): Ditto. (vint16mf4_t): Ditto. (vuint16mf4_t): Ditto. (vint16mf2_t): Ditto. (vuint16mf2_t): Ditto. (vint16m1_t): Ditto. (vuint16m1_t): Ditto. (vint16m2_t): Ditto. (vuint16m2_t): Ditto. (vint16m4_t): Ditto. (vuint16m4_t): Ditto. (vint16m8_t): Ditto. (vuint16m8_t): Ditto. (vint32mf2_t): Ditto. (vuint32mf2_t): Ditto. (vint32m1_t): Ditto. (vuint32m1_t): Ditto. (vint32m2_t): Ditto. (vuint32m2_t): Ditto. (vint32m4_t): Ditto. (vuint32m4_t): Ditto. (vint32m8_t): Ditto. (vuint32m8_t): Ditto. (vint64m1_t): Ditto. (vuint64m1_t): Ditto. (vint64m2_t): Ditto. (vuint64m2_t): Ditto. (vint64m4_t): Ditto. (vuint64m4_t): Ditto. (vint64m8_t): Ditto. (vuint64m8_t): Ditto. (vfloat32mf2_t): Ditto. (vfloat32m1_t): Ditto. (vfloat32m2_t): Ditto. (vfloat32m4_t): Ditto. (vfloat32m8_t): Ditto. (vfloat64m1_t): Ditto. (vfloat64m2_t): Ditto. (vfloat64m4_t): Ditto. (vfloat64m8_t): Ditto. (vv): Ditto. (vx): Ditto. (v): Ditto. (wv): Ditto. (wx): Ditto. (x_x_v): Ditto. (vf2): Ditto. (vf4): Ditto. (vf8): Ditto. (vvm): Ditto. (vxm): Ditto. (x_x_w): Ditto. (v_v): Ditto. (v_x): Ditto. (vs): Ditto. (mm): Ditto. (m): Ditto. (vf): Ditto. (vm): Ditto. (wf): Ditto. (vfm): Ditto. (v_f): Ditto. (ta): Ditto. (tu): Ditto. (ma): Ditto. (mu): Ditto. (tama): Ditto. (tamu): Ditto. (tuma): Ditto. (tumu): Ditto. (tam): Ditto. (tum): Ditto. * config/riscv/riscv-vector-builtins.h (GCC_RISCV_VECTOR_BUILTINS_H): New macro. (RVV_REQUIRE_RV64BIT): Ditto. (RVV_REQUIRE_ZVE64): Ditto. (RVV_REQUIRE_ELEN_FP_32): Ditto. (RVV_REQUIRE_ELEN_FP_64): Ditto. (enum operand_type_index): New enum. (DEF_RVV_OP_TYPE): New macro. (enum predication_type_index): New enum. (DEF_RVV_PRED_TYPE): New macro. (enum rvv_base_type): New enum. (struct rvv_builtin_suffixes): New struct. (struct rvv_arg_type_info): Ditto. (struct rvv_type_info): Ditto. (struct rvv_op_info): Ditto. (class registered_function): New class. (class function_base): Ditto. (class function_shape): Ditto. (struct function_group_info): New struct. (class GTY): New class. (class function_builder): Ditto. (class function_call_info): Ditto. (function_call_info::function_returns_void_p): New function. (class function_expander): New class. (function_instance::operator!=): New function. (function_expander::expand): Ditto. (function_expander::add_input_operand): Ditto. (function_base::call_properties): Ditto. Diff: --- gcc/config.gcc | 2 + gcc/config/riscv/riscv-builtins.cc | 44 ++- gcc/config/riscv/riscv-protos.h | 17 ++ gcc/config/riscv/riscv-vector-builtins.cc | 475 ++++++++++++++++++++++++++++- gcc/config/riscv/riscv-vector-builtins.def | 245 ++++++++++----- gcc/config/riscv/riscv-vector-builtins.h | 363 ++++++++++++++++++++++ 6 files changed, 1065 insertions(+), 81 deletions(-) diff --git a/gcc/config.gcc b/gcc/config.gcc index 3950b416903..acd1a74c5f7 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -520,6 +520,8 @@ riscv*) extra_objs="${extra_objs} riscv-vector-builtins.o" d_target_objs="riscv-d.o" extra_headers="riscv_vector.h" + target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc" + target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.h" ;; rs6000*-*-*) extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 14865d70955..9fa4d6cffd8 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -223,7 +223,10 @@ riscv_init_builtins (void) { tree type = riscv_build_function_type (d->prototype); riscv_builtin_decls[i] - = add_builtin_function (d->name, type, i, BUILT_IN_MD, NULL, NULL); + = add_builtin_function (d->name, type, + (i << RISCV_BUILTIN_SHIFT) + + RISCV_BUILTIN_GENERAL, + BUILT_IN_MD, NULL, NULL); riscv_builtin_decl_index[d->icode] = i; } } @@ -234,9 +237,18 @@ riscv_init_builtins (void) tree riscv_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED) { - if (code >= ARRAY_SIZE (riscv_builtins)) - return error_mark_node; - return riscv_builtin_decls[code]; + unsigned int subcode = code >> RISCV_BUILTIN_SHIFT; + switch (code & RISCV_BUILTIN_CLASS) + { + case RISCV_BUILTIN_GENERAL: + if (subcode >= ARRAY_SIZE (riscv_builtins)) + return error_mark_node; + return riscv_builtin_decls[subcode]; + + case RISCV_BUILTIN_VECTOR: + return riscv_vector::builtin_decl (subcode, initialize_p); + } + return error_mark_node; } /* Take argument ARGNO from EXP's argument list and convert it into @@ -303,15 +315,23 @@ riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl); - const struct riscv_builtin_description *d = &riscv_builtins[fcode]; - - switch (d->builtin_type) + unsigned int subcode = fcode >> RISCV_BUILTIN_SHIFT; + switch (fcode & RISCV_BUILTIN_CLASS) { - case RISCV_BUILTIN_DIRECT: - return riscv_expand_builtin_direct (d->icode, target, exp, true); - - case RISCV_BUILTIN_DIRECT_NO_TARGET: - return riscv_expand_builtin_direct (d->icode, target, exp, false); + case RISCV_BUILTIN_VECTOR: + return riscv_vector::expand_builtin (subcode, exp, target); + case RISCV_BUILTIN_GENERAL: { + const struct riscv_builtin_description *d = &riscv_builtins[subcode]; + + switch (d->builtin_type) + { + case RISCV_BUILTIN_DIRECT: + return riscv_expand_builtin_direct (d->icode, target, exp, true); + + case RISCV_BUILTIN_DIRECT_NO_TARGET: + return riscv_expand_builtin_direct (d->icode, target, exp, false); + } + } } gcc_unreachable (); diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index a44b34d1278..f8c9932ff89 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -124,6 +124,23 @@ extern const char *mangle_builtin_type (const_tree); extern bool verify_type_context (location_t, type_context_kind, const_tree, bool); #endif extern void handle_pragma_vector (void); +extern tree builtin_decl (unsigned, bool); +extern rtx expand_builtin (unsigned int, tree, rtx); } +/* We classify builtin types into two classes: + 1. General builtin class which is defined in riscv_builtins. + 2. Vector builtin class which is a special builtin architecture + that implement intrinsic short into "pragma". */ +enum riscv_builtin_class +{ + RISCV_BUILTIN_GENERAL, + RISCV_BUILTIN_VECTOR +}; + +const unsigned int RISCV_BUILTIN_SHIFT = 1; + +/* Mask that selects the riscv_builtin_class part of a function code. */ +const unsigned int RISCV_BUILTIN_CLASS = (1 << RISCV_BUILTIN_SHIFT) - 1; + #endif /* ! GCC_RISCV_PROTOS_H */ diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 55d45651618..5c20788b3ab 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -66,13 +66,55 @@ struct vector_type_info const char *mangled_name; }; -/* Information about each RVV type. */ +/* Describes a function decl. */ +class GTY (()) registered_function +{ +public: + function_instance GTY ((skip)) instance; + + /* The decl itself. */ + tree GTY ((skip)) decl; +}; + +/* Hash traits for registered_function. */ +struct registered_function_hasher : nofree_ptr_hash +{ + typedef function_instance compare_type; + + static hashval_t hash (value_type); + static bool equal (value_type, const compare_type &); +}; + +/* Static information about each RVV type. */ static CONSTEXPR const vector_type_info vector_types[] = { #define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, ARGS...) \ {#NAME, #ABI_NAME, "u" #NCHARS #ABI_NAME}, #include "riscv-vector-builtins.def" }; +/* Static information about operand suffix for each RVV type. */ +const char *const operand_suffixes[NUM_OP_TYPES] = { + "", /* OP_TYPE_none. */ +#define DEF_RVV_OP_TYPE(NAME) "_" # NAME, +#include "riscv-vector-builtins.def" +}; + +/* Static information about type suffix for each RVV type. */ +const rvv_builtin_suffixes type_suffixes[NUM_VECTOR_TYPES + 1] = { +#define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \ + VECTOR_MODE_MIN_VLEN_32, VECTOR_SUFFIX, SCALAR_SUFFIX, \ + VSETVL_SUFFIX) \ + {#VECTOR_SUFFIX, #SCALAR_SUFFIX, #VSETVL_SUFFIX}, +#include "riscv-vector-builtins.def" +}; + +/* Static information about predication suffix for each RVV type. */ +const char *const predication_suffixes[NUM_PRED_TYPES] = { + "", /* PRED_TYPE_none. */ +#define DEF_RVV_PRED_TYPE(NAME) "_" # NAME, +#include "riscv-vector-builtins.def" +}; + /* The RVV types, with their built-in "__rvv..._t" name. Allow an index of NUM_VECTOR_TYPES, which always yields a null tree. */ @@ -82,6 +124,14 @@ static GTY (()) tree abi_vector_types[NUM_VECTOR_TYPES + 1]; extern GTY (()) rvv_builtin_types_t builtin_types[NUM_VECTOR_TYPES + 1]; rvv_builtin_types_t builtin_types[NUM_VECTOR_TYPES + 1]; +/* The list of all registered function decls, indexed by code. */ +static GTY (()) vec *registered_functions; + +/* All registered function decls, hashed on the function_instance + that they implement. This is used for looking up implementations of + overloaded functions. */ +static hash_table *function_table; + /* RAII class for enabling enough RVV features to define the built-in types and implement the riscv_vector.h pragma. @@ -118,6 +168,13 @@ rvv_switcher::~rvv_switcher () sizeof (have_regs_of_mode)); } +/* Add attribute NAME to ATTRS. */ +static tree +add_attribute (const char *name, tree attrs) +{ + return tree_cons (get_identifier (name), NULL_TREE, attrs); +} + /* Add type attributes to builtin type tree, currently only the mangled name. */ static void add_vector_type_attribute (tree type, const char *mangled_name) @@ -215,6 +272,7 @@ static void register_vector_type (vector_type_index type) { tree vectype = abi_vector_types[type]; + /* When vectype is NULL, the corresponding builtin type is disabled according to '-march'. */ if (!vectype) @@ -237,6 +295,386 @@ register_vector_type (vector_type_index type) builtin_types[type].vector_ptr = build_pointer_type (vectype); } +/* Check whether all the RVV_REQUIRE_* values in REQUIRED_EXTENSIONS are + enabled. */ +static bool +check_required_extensions (uint64_t required_extensions) +{ + uint64_t riscv_isa_flags = 0; + + if (TARGET_VECTOR_ELEN_FP_32) + riscv_isa_flags |= RVV_REQUIRE_ELEN_FP_32; + if (TARGET_VECTOR_ELEN_FP_64) + riscv_isa_flags |= RVV_REQUIRE_ELEN_FP_64; + if (TARGET_MIN_VLEN > 32) + riscv_isa_flags |= RVV_REQUIRE_ZVE64; + if (TARGET_64BIT) + riscv_isa_flags |= RVV_REQUIRE_RV64BIT; + + uint64_t missing_extensions = required_extensions & ~riscv_isa_flags; + if (missing_extensions != 0) + return false; + return true; +} + +tree +rvv_arg_type_info::get_tree_type (vector_type_index type_idx) const +{ + switch (base_type) + { + case RVV_BASE_vector: + return builtin_types[type_idx].vector; + case RVV_BASE_scalar: + return builtin_types[type_idx].scalar; + case RVV_BASE_vector_ptr: + return builtin_types[type_idx].vector_ptr; + case RVV_BASE_scalar_ptr: + return builtin_types[type_idx].scalar_ptr; + case RVV_BASE_scalar_const_ptr: + return builtin_types[type_idx].scalar_const_ptr; + case RVV_BASE_void: + return void_type_node; + case RVV_BASE_size: + return size_type_node; + case RVV_BASE_ptrdiff: + return ptrdiff_type_node; + case RVV_BASE_unsigned_long: + return long_unsigned_type_node; + case RVV_BASE_long: + return long_integer_type_node; + default: + gcc_unreachable (); + } +} + +function_instance::function_instance (const char *base_name_in, + const function_base *base_in, + const function_shape *shape_in, + rvv_type_info type_in, + predication_type_index pred_in, + const rvv_op_info *op_info_in) + : base_name (base_name_in), base (base_in), shape (shape_in), type (type_in), + pred (pred_in), op_info (op_info_in) +{ +} + +bool +function_instance::operator== (const function_instance &other) const +{ + for (unsigned int i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i) + if (op_info->args[i].base_type != other.op_info->args[i].base_type) + return false; + return (base == other.base && shape == other.shape + && type.index == other.type.index && op_info->op == other.op_info->op + && pred == other.pred + && op_info->ret.base_type == other.op_info->ret.base_type); +} + +bool +function_instance::any_type_float_p () const +{ + if (FLOAT_MODE_P (TYPE_MODE (get_return_type ()))) + return true; + + for (int i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i) + if (FLOAT_MODE_P (TYPE_MODE (get_arg_type (i)))) + return true; + + return false; +} + +tree +function_instance::get_return_type () const +{ + return op_info->ret.get_tree_type (type.index); +} + +tree +function_instance::get_arg_type (unsigned opno) const +{ + return op_info->args[opno].get_tree_type (type.index); +} + +/* Return a hash code for a function_instance. */ +hashval_t +function_instance::hash () const +{ + inchash::hash h; + /* BASE uniquely determines BASE_NAME, so we don't need to hash both. */ + h.add_ptr (base); + h.add_ptr (shape); + h.add_int (type.index); + h.add_int (op_info->op); + h.add_int (pred); + h.add_int (op_info->ret.base_type); + for (unsigned int i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i) + h.add_int (op_info->args[i].base_type); + return h.end (); +} + +/* Return a set of CP_* flags that describe what the function could do, + taking the command-line flags into account. */ +unsigned int +function_instance::call_properties () const +{ + unsigned int flags = base->call_properties (*this); + + /* -fno-trapping-math means that we can assume any FP exceptions + are not user-visible. */ + if (!flag_trapping_math) + flags &= ~CP_RAISE_FP_EXCEPTIONS; + + return flags; +} + +/* Return true if calls to the function could read some form of + global state. */ +bool +function_instance::reads_global_state_p () const +{ + unsigned int flags = call_properties (); + + /* Preserve any dependence on rounding mode, flush to zero mode, etc. + There is currently no way of turning this off; in particular, + -fno-rounding-math (which is the default) means that we should make + the usual assumptions about rounding mode, which for intrinsics means + acting as the instructions do. */ + if (flags & CP_READ_FPCR) + return true; + + /* Handle direct reads of global state. */ + return flags & (CP_READ_MEMORY | CP_READ_CSR); +} + +/* Return true if calls to the function could modify some form of + global state. */ +bool +function_instance::modifies_global_state_p () const +{ + unsigned int flags = call_properties (); + + /* Preserve any exception state written back to the FPCR, + unless -fno-trapping-math says this is unnecessary. */ + if (flags & CP_RAISE_FP_EXCEPTIONS) + return true; + + /* Handle direct modifications of global state. */ + return flags & (CP_WRITE_MEMORY | CP_WRITE_CSR); +} + +/* Return true if calls to the function could raise a signal. */ +bool +function_instance::could_trap_p () const +{ + unsigned int flags = call_properties (); + + /* Handle functions that could raise SIGFPE. */ + if (flags & CP_RAISE_FP_EXCEPTIONS) + return true; + + /* Handle functions that could raise SIGBUS or SIGSEGV. */ + if (flags & (CP_READ_MEMORY | CP_WRITE_MEMORY)) + return true; + + return false; +} + +function_builder::function_builder () +{ + m_direct_overloads = lang_GNU_CXX (); + gcc_obstack_init (&m_string_obstack); +} + +function_builder::~function_builder () +{ + obstack_free (&m_string_obstack, NULL); +} + +/* Allocate arguments of the function. */ +void +function_builder::allocate_argument_types (const function_instance &instance, + vec &argument_types) const +{ + for (unsigned int i = 0; + instance.op_info->args[i].base_type != NUM_BASE_TYPES; ++i) + argument_types.quick_push ( + instance.op_info->args[i].get_tree_type (instance.type.index)); +} + +/* Register all the functions in GROUP. */ +void +function_builder::register_function_group (const function_group_info &group) +{ + (*group.shape)->build (*this, group); +} + +/* Add NAME to the end of the function name being built. */ +void +function_builder::append_name (const char *name) +{ + obstack_grow (&m_string_obstack, name, strlen (name)); +} + +/* Zero-terminate and complete the function name being built. */ +char * +function_builder::finish_name () +{ + obstack_1grow (&m_string_obstack, 0); + return (char *) obstack_finish (&m_string_obstack); +} + +/* Return the appropriate function attributes for INSTANCE. */ +tree +function_builder::get_attributes (const function_instance &instance) +{ + tree attrs = NULL_TREE; + + if (!instance.modifies_global_state_p ()) + { + if (instance.reads_global_state_p ()) + attrs = add_attribute ("pure", attrs); + else + attrs = add_attribute ("const", attrs); + } + + if (!flag_non_call_exceptions || !instance.could_trap_p ()) + attrs = add_attribute ("nothrow", attrs); + + return add_attribute ("leaf", attrs); +} + +/* Add a function called NAME with type FNTYPE and attributes ATTRS. + INSTANCE describes what the function does. */ +registered_function & +function_builder::add_function (const function_instance &instance, + const char *name, tree fntype, tree attrs, + bool placeholder_p) +{ + unsigned int code = vec_safe_length (registered_functions); + code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR; + + /* We need to be able to generate placeholders to enusre that we have a + consistent numbering scheme for function codes between the C and C++ + frontends, so that everything ties up in LTO. + + Currently, tree-streamer-in.c:unpack_ts_function_decl_value_fields + validates that tree nodes returned by TARGET_BUILTIN_DECL are non-NULL and + some node other than error_mark_node. This is a holdover from when builtin + decls were streamed by code rather than by value. + + Ultimately, we should be able to remove this validation of BUILT_IN_MD + nodes and remove the target hook. For now, however, we need to appease the + validation and return a non-NULL, non-error_mark_node node, so we + arbitrarily choose integer_zero_node. */ + tree decl = placeholder_p + ? integer_zero_node + : simulate_builtin_function_decl (input_location, name, fntype, + code, NULL, attrs); + + registered_function &rfn = *ggc_alloc (); + rfn.instance = instance; + rfn.decl = decl; + vec_safe_push (registered_functions, &rfn); + + return rfn; +} + +/* Add a built-in function for INSTANCE, with the argument types given + by ARGUMENT_TYPES and the return type given by RETURN_TYPE. NAME is + the "full" name for C function. OVERLOAD_NAME is the "short" name for + C++ overloaded function. OVERLOAD_NAME can be nullptr because some + instance doesn't have C++ overloaded function. */ +void +function_builder::add_unique_function (const function_instance &instance, + const function_shape *shape, + tree return_type, + vec &argument_types) +{ + /* Do not add this function if it is invalid. */ + if (!check_required_extensions (instance.type.required_extensions)) + return; + + /* Add the function under its full (unique) name. */ + char *name = shape->get_name (*this, instance, false); + tree fntype + = build_function_type_array (return_type, argument_types.length (), + argument_types.address ()); + tree attrs = get_attributes (instance); + registered_function &rfn + = add_function (instance, name, fntype, attrs, false); + + /* Enter the function into the hash table. */ + hashval_t hash = instance.hash (); + registered_function **rfn_slot + = function_table->find_slot_with_hash (instance, hash, INSERT); + gcc_assert (!*rfn_slot); + *rfn_slot = &rfn; + + /* Also add the function under its overloaded alias, if we want + a separate decl for each instance of an overloaded function. */ + char *overload_name = shape->get_name (*this, instance, true); + if (overload_name) + { + /* Attribute lists shouldn't be shared. */ + tree attrs = get_attributes (instance); + bool placeholder_p = !m_direct_overloads; + add_function (instance, overload_name, fntype, attrs, placeholder_p); + } + obstack_free (&m_string_obstack, name); +} + +function_call_info::function_call_info (location_t location_in, + const function_instance &instance_in, + tree fndecl_in) + : function_instance (instance_in), location (location_in), fndecl (fndecl_in) +{} + +function_expander::function_expander (const function_instance &instance, + tree fndecl_in, tree exp_in, + rtx target_in) + : function_call_info (EXPR_LOCATION (exp_in), instance, fndecl_in), + exp (exp_in), target (target_in), opno (0) +{ + if (!function_returns_void_p ()) + create_output_operand (&m_ops[opno++], target, TYPE_MODE (TREE_TYPE (exp))); +} + +/* Take argument ARGNO from EXP's argument list and convert it into + an expand operand. Store the operand in *M_OPS. */ +void +function_expander::add_input_operand (unsigned argno) +{ + tree arg = CALL_EXPR_ARG (exp, argno); + rtx x = expand_normal (arg); + add_input_operand (TYPE_MODE (TREE_TYPE (arg)), x); +} + +/* Generate instruction ICODE, given that its operands have already + been added to M_OPS. Return the value of the first operand. */ +rtx +function_expander::generate_insn (insn_code icode) +{ + gcc_assert (opno == insn_data[icode].n_generator_args); + if (!maybe_expand_insn (icode, opno, m_ops)) + { + error ("invalid argument to built-in function"); + return NULL_RTX; + } + return function_returns_void_p () ? const0_rtx : m_ops[0].value; +} + +inline hashval_t +registered_function_hasher::hash (value_type value) +{ + return value->instance.hash (); +} + +inline bool +registered_function_hasher::equal (value_type value, const compare_type &key) +{ + return value->instance == key; +} + /* If TYPE is a built-in type defined by the RVV ABI, return the mangled name, otherwise return NULL. */ const char * @@ -356,4 +794,39 @@ handle_pragma_vector () register_vector_type ((enum vector_type_index) type_i); } +/* Return the function decl with RVV function subcode CODE, or error_mark_node + if no such function exists. */ +tree +builtin_decl (unsigned int code, bool) +{ + if (code >= vec_safe_length (registered_functions)) + return error_mark_node; + + return (*registered_functions)[code]->decl; +} + +/* Expand a call to the RVV function with subcode CODE. EXP is the call + expression and TARGET is the preferred location for the result. + Return the value of the lhs. */ +rtx +expand_builtin (unsigned int code, tree exp, rtx target) +{ + registered_function &rfn = *(*registered_functions)[code]; + return function_expander (rfn.instance, rfn.decl, exp, target).expand (); +} + } // end namespace riscv_vector + +inline void +gt_ggc_mx (function_instance *) +{} + +inline void +gt_pch_nx (function_instance *) +{} + +inline void +gt_pch_nx (function_instance *, gt_pointer_operator, void *) +{} + +#include "gt-riscv-vector-builtins.h" diff --git a/gcc/config/riscv/riscv-vector-builtins.def b/gcc/config/riscv/riscv-vector-builtins.def index 83603fedd57..b7a633ed376 100644 --- a/gcc/config/riscv/riscv-vector-builtins.def +++ b/gcc/config/riscv/riscv-vector-builtins.def @@ -19,181 +19,290 @@ along with GCC; see the file COPYING3. If not see . */ /* Use "DEF_RVV_TYPE" macro to define RVV datatype builtins. - 1.The 1 argument is the name exposed to users. + 1.The 'NAME' argument is the name exposed to users. For example, "vint32m1_t". - 2.The 2 argument is the length of ABI-name. + 2.The 'NCHARS' argument is the length of ABI-name. For example, length of "__rvv_int32m1_t" is 15. - 3.The 3 argument is the ABI-name. For example, "__rvv_int32m1_t". - 4.The 4 argument is associated scalar type which is used in + 3.The 'ABI_NAME' argument is the ABI-name. For example, "__rvv_int32m1_t". + 4.The 'SCALAR_TYPE' argument is associated scalar type which is used in "build_vector_type_for_mode". For "vint32m1_t", we use "intSI_type_node" in RV64. Otherwise, we use "long_integer_type_node". - 5.The 5 and 6 argument are the machine modes of corresponding RVV type used - in "build_vector_type_for_mode". For "vint32m1_t", we use VNx2SImode when - TARGET_MIN_VLEN > 32. Otherwise the machine mode is VNx1SImode. */ + 5.The 'VECTOR_MODE' is the machine modes of corresponding RVV type used + in "build_vector_type_for_mode" when TARGET_MIN_VLEN > 32. + For example: VECTOR_MODE = VNx2SI for "vint32m1_t". + 6.The 'VECTOR_MODE_MIN_VLEN_32' is the machine modes of corresponding RVV + type used in "build_vector_type_for_mode" when TARGET_MIN_VLEN = 32. For + example: VECTOR_MODE_MIN_VLEN_32 = VNx1SI for "vint32m1_t". + 7.The 'VECTOR_SUFFIX' define mode suffix for vector type. + For example: type_suffixes[VECTOR_TYPE_vin32m1_t].vector = i32m1. + 8.The 'SCALAR_SUFFIX' define mode suffix for scalar type. + For example: type_suffixes[VECTOR_TYPE_vin32m1_t].scalar = i32. + 9.The 'VSETVL_SUFFIX' define mode suffix for vsetvli instruction. + For example: type_suffixes[VECTOR_TYPE_vin32m1_t].vsetvl = e32m1. +*/ #ifndef DEF_RVV_TYPE #define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \ - VECTOR_MODE_MIN_VLEN_32) + VECTOR_MODE_MIN_VLEN_32, VECTOR_SUFFIX, SCALAR_SUFFIX, \ + VSETVL_SUFFIX) +#endif + +/* Use "DEF_RVV_OP_TYPE" macro to define RVV operand types. + The 'NAME' will be concatenated into intrinsic function name. */ +#ifndef DEF_RVV_OP_TYPE +#define DEF_RVV_OP_TYPE(NAME) +#endif + +/* Use "DEF_RVV_PRED_TYPE" macro to define RVV predication types. + The 'NAME' will be concatenated into intrinsic function name. */ +#ifndef DEF_RVV_PRED_TYPE +#define DEF_RVV_PRED_TYPE(NAME) #endif /* SEW/LMUL = 64: Only enable when TARGET_MIN_VLEN > 32 and machine mode = VNx1BImode. */ -DEF_RVV_TYPE (vbool64_t, 14, __rvv_bool64_t, boolean, VNx1BI, VOID) +DEF_RVV_TYPE (vbool64_t, 14, __rvv_bool64_t, boolean, VNx1BI, VOID, _b64, , ) /* SEW/LMUL = 32: Machine mode = VNx2BImode when TARGET_MIN_VLEN > 32. Machine mode = VNx1BImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vbool32_t, 14, __rvv_bool32_t, boolean, VNx2BI, VNx1BI) +DEF_RVV_TYPE (vbool32_t, 14, __rvv_bool32_t, boolean, VNx2BI, VNx1BI, _b32, , ) /* SEW/LMUL = 16: Machine mode = VNx2BImode when TARGET_MIN_VLEN = 32. Machine mode = VNx4BImode when TARGET_MIN_VLEN > 32. */ -DEF_RVV_TYPE (vbool16_t, 14, __rvv_bool16_t, boolean, VNx4BI, VNx2BI) +DEF_RVV_TYPE (vbool16_t, 14, __rvv_bool16_t, boolean, VNx4BI, VNx2BI, _b16, , ) /* SEW/LMUL = 8: Machine mode = VNx8BImode when TARGET_MIN_VLEN > 32. Machine mode = VNx4BImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vbool8_t, 13, __rvv_bool8_t, boolean, VNx8BI, VNx4BI) +DEF_RVV_TYPE (vbool8_t, 13, __rvv_bool8_t, boolean, VNx8BI, VNx4BI, _b8, , ) /* SEW/LMUL = 4: Machine mode = VNx16BImode when TARGET_MIN_VLEN > 32. Machine mode = VNx8BImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vbool4_t, 13, __rvv_bool4_t, boolean, VNx16BI, VNx8BI) +DEF_RVV_TYPE (vbool4_t, 13, __rvv_bool4_t, boolean, VNx16BI, VNx8BI, _b4, , ) /* SEW/LMUL = 2: Machine mode = VNx32BImode when TARGET_MIN_VLEN > 32. Machine mode = VNx16BImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vbool2_t, 13, __rvv_bool2_t, boolean, VNx32BI, VNx16BI) +DEF_RVV_TYPE (vbool2_t, 13, __rvv_bool2_t, boolean, VNx32BI, VNx16BI, _b2, , ) /* SEW/LMUL = 1: Machine mode = VNx64BImode when TARGET_MIN_VLEN > 32. Machine mode = VNx32BImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vbool1_t, 13, __rvv_bool1_t, boolean, VNx64BI, VNx32BI) +DEF_RVV_TYPE (vbool1_t, 13, __rvv_bool1_t, boolean, VNx64BI, VNx32BI, _b1, , ) /* LMUL = 1/8: Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1QImode. */ -DEF_RVV_TYPE (vint8mf8_t, 15, __rvv_int8mf8_t, intQI, VNx1QI, VOID) -DEF_RVV_TYPE (vuint8mf8_t, 16, __rvv_uint8mf8_t, unsigned_intQI, VNx1QI, VOID) +DEF_RVV_TYPE (vint8mf8_t, 15, __rvv_int8mf8_t, intQI, VNx1QI, VOID, _i8mf8, _i8, + _e8mf8) +DEF_RVV_TYPE (vuint8mf8_t, 16, __rvv_uint8mf8_t, unsigned_intQI, VNx1QI, VOID, + _u8mf8, _u8, _e8mf8) /* LMUL = 1/4: Machine mode = VNx2QImode when TARGET_MIN_VLEN > 32. Machine mode = VNx1QImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint8mf4_t, 15, __rvv_int8mf4_t, intQI, VNx2QI, VNx1QI) -DEF_RVV_TYPE (vuint8mf4_t, 16, __rvv_uint8mf4_t, unsigned_intQI, VNx2QI, VNx1QI) +DEF_RVV_TYPE (vint8mf4_t, 15, __rvv_int8mf4_t, intQI, VNx2QI, VNx1QI, _i8mf4, + _i8, _e8mf4) +DEF_RVV_TYPE (vuint8mf4_t, 16, __rvv_uint8mf4_t, unsigned_intQI, VNx2QI, VNx1QI, + _u8mf4, _u8, _e8mf4) /* LMUL = 1/2: Machine mode = VNx4QImode when TARGET_MIN_VLEN > 32. Machine mode = VNx2QImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint8mf2_t, 15, __rvv_int8mf2_t, intQI, VNx4QI, VNx2QI) -DEF_RVV_TYPE (vuint8mf2_t, 16, __rvv_uint8mf2_t, unsigned_intQI, VNx4QI, VNx2QI) +DEF_RVV_TYPE (vint8mf2_t, 15, __rvv_int8mf2_t, intQI, VNx4QI, VNx2QI, _i8mf2, + _i8, _e8mf2) +DEF_RVV_TYPE (vuint8mf2_t, 16, __rvv_uint8mf2_t, unsigned_intQI, VNx4QI, VNx2QI, + _u8mf2, _u8, _e8mf2) /* LMUL = 1: Machine mode = VNx8QImode when TARGET_MIN_VLEN > 32. Machine mode = VNx4QImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint8m1_t, 14, __rvv_int8m1_t, intQI, VNx8QI, VNx4QI) -DEF_RVV_TYPE (vuint8m1_t, 15, __rvv_uint8m1_t, unsigned_intQI, VNx8QI, VNx4QI) +DEF_RVV_TYPE (vint8m1_t, 14, __rvv_int8m1_t, intQI, VNx8QI, VNx4QI, _i8m1, _i8, + _e8m1) +DEF_RVV_TYPE (vuint8m1_t, 15, __rvv_uint8m1_t, unsigned_intQI, VNx8QI, VNx4QI, + _u8m1, _u8, _e8m1) /* LMUL = 2: Machine mode = VNx16QImode when TARGET_MIN_VLEN > 32. Machine mode = VNx8QImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint8m2_t, 14, __rvv_int8m2_t, intQI, VNx16QI, VNx8QI) -DEF_RVV_TYPE (vuint8m2_t, 15, __rvv_uint8m2_t, unsigned_intQI, VNx16QI, VNx8QI) +DEF_RVV_TYPE (vint8m2_t, 14, __rvv_int8m2_t, intQI, VNx16QI, VNx8QI, _i8m2, _i8, + _e8m2) +DEF_RVV_TYPE (vuint8m2_t, 15, __rvv_uint8m2_t, unsigned_intQI, VNx16QI, VNx8QI, + _u8m2, _u8, _e8m2) /* LMUL = 4: Machine mode = VNx32QImode when TARGET_MIN_VLEN > 32. Machine mode = VNx16QImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint8m4_t, 14, __rvv_int8m4_t, intQI, VNx32QI, VNx16QI) -DEF_RVV_TYPE (vuint8m4_t, 15, __rvv_uint8m4_t, unsigned_intQI, VNx32QI, VNx16QI) +DEF_RVV_TYPE (vint8m4_t, 14, __rvv_int8m4_t, intQI, VNx32QI, VNx16QI, _i8m4, + _i8, _e8m4) +DEF_RVV_TYPE (vuint8m4_t, 15, __rvv_uint8m4_t, unsigned_intQI, VNx32QI, VNx16QI, + _u8m4, _u8, _e8m4) /* LMUL = 8: Machine mode = VNx64QImode when TARGET_MIN_VLEN > 32. Machine mode = VNx32QImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint8m8_t, 14, __rvv_int8m8_t, intQI, VNx64QI, VNx32QI) -DEF_RVV_TYPE (vuint8m8_t, 15, __rvv_uint8m8_t, unsigned_intQI, VNx64QI, VNx32QI) +DEF_RVV_TYPE (vint8m8_t, 14, __rvv_int8m8_t, intQI, VNx64QI, VNx32QI, _i8m8, + _i8, _e8m8) +DEF_RVV_TYPE (vuint8m8_t, 15, __rvv_uint8m8_t, unsigned_intQI, VNx64QI, VNx32QI, + _u8m8, _u8, _e8m8) /* LMUL = 1/4: Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1HImode. */ -DEF_RVV_TYPE (vint16mf4_t, 16, __rvv_int16mf4_t, intHI, VNx1HI, VOID) -DEF_RVV_TYPE (vuint16mf4_t, 17, __rvv_uint16mf4_t, unsigned_intHI, VNx1HI, VOID) +DEF_RVV_TYPE (vint16mf4_t, 16, __rvv_int16mf4_t, intHI, VNx1HI, VOID, _i16mf4, + _i16, _e16mf4) +DEF_RVV_TYPE (vuint16mf4_t, 17, __rvv_uint16mf4_t, unsigned_intHI, VNx1HI, VOID, + _u16mf4, _u16, _e16mf4) /* LMUL = 1/2: Machine mode = VNx2HImode when TARGET_MIN_VLEN > 32. Machine mode = VNx1HImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint16mf2_t, 16, __rvv_int16mf2_t, intHI, VNx2HI, VNx1HI) +DEF_RVV_TYPE (vint16mf2_t, 16, __rvv_int16mf2_t, intHI, VNx2HI, VNx1HI, _i16mf2, + _i16, _e16mf2) DEF_RVV_TYPE (vuint16mf2_t, 17, __rvv_uint16mf2_t, unsigned_intHI, VNx2HI, - VNx1HI) + VNx1HI, _u16mf2, _u16, _e16mf2) /* LMUL = 1: Machine mode = VNx4HImode when TARGET_MIN_VLEN > 32. Machine mode = VNx2HImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint16m1_t, 15, __rvv_int16m1_t, intHI, VNx4HI, VNx2HI) -DEF_RVV_TYPE (vuint16m1_t, 16, __rvv_uint16m1_t, unsigned_intHI, VNx4HI, VNx2HI) +DEF_RVV_TYPE (vint16m1_t, 15, __rvv_int16m1_t, intHI, VNx4HI, VNx2HI, _i16m1, + _i16, _e16m1) +DEF_RVV_TYPE (vuint16m1_t, 16, __rvv_uint16m1_t, unsigned_intHI, VNx4HI, VNx2HI, + _u16m1, _u16, _e16m1) /* LMUL = 2: Machine mode = VNx8HImode when TARGET_MIN_VLEN > 32. Machine mode = VNx4HImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint16m2_t, 15, __rvv_int16m2_t, intHI, VNx8HI, VNx4HI) -DEF_RVV_TYPE (vuint16m2_t, 16, __rvv_uint16m2_t, unsigned_intHI, VNx8HI, VNx4HI) +DEF_RVV_TYPE (vint16m2_t, 15, __rvv_int16m2_t, intHI, VNx8HI, VNx4HI, _i16m2, + _i16, _e16m2) +DEF_RVV_TYPE (vuint16m2_t, 16, __rvv_uint16m2_t, unsigned_intHI, VNx8HI, VNx4HI, + _u16m2, _u16, _e16m2) /* LMUL = 4: Machine mode = VNx16HImode when TARGET_MIN_VLEN > 32. Machine mode = VNx8HImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint16m4_t, 15, __rvv_int16m4_t, intHI, VNx16HI, VNx8HI) +DEF_RVV_TYPE (vint16m4_t, 15, __rvv_int16m4_t, intHI, VNx16HI, VNx8HI, _i16m4, + _i16, _e16m4) DEF_RVV_TYPE (vuint16m4_t, 16, __rvv_uint16m4_t, unsigned_intHI, VNx16HI, - VNx8HI) + VNx8HI, _u16m4, _u16, _e16m4) /* LMUL = 8: Machine mode = VNx32HImode when TARGET_MIN_VLEN > 32. Machine mode = VNx16HImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint16m8_t, 15, __rvv_int16m8_t, intHI, VNx32HI, VNx16HI) +DEF_RVV_TYPE (vint16m8_t, 15, __rvv_int16m8_t, intHI, VNx32HI, VNx16HI, _i16m8, + _i16, _e16m8) DEF_RVV_TYPE (vuint16m8_t, 16, __rvv_uint16m8_t, unsigned_intHI, VNx32HI, - VNx16HI) + VNx16HI, _u16m8, _u16, _e16m8) /* LMUL = 1/2: Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1SImode. */ -DEF_RVV_TYPE (vint32mf2_t, 16, __rvv_int32mf2_t, int32, VNx1SI, VOID) -DEF_RVV_TYPE (vuint32mf2_t, 17, __rvv_uint32mf2_t, unsigned_int32, VNx1SI, VOID) +DEF_RVV_TYPE (vint32mf2_t, 16, __rvv_int32mf2_t, int32, VNx1SI, VOID, _i32mf2, + _i32, _e32mf2) +DEF_RVV_TYPE (vuint32mf2_t, 17, __rvv_uint32mf2_t, unsigned_int32, VNx1SI, VOID, + _u32mf2, _u32, _e32mf2) /* LMUL = 1: Machine mode = VNx2SImode when TARGET_MIN_VLEN > 32. Machine mode = VNx1SImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint32m1_t, 15, __rvv_int32m1_t, int32, VNx2SI, VNx1SI) -DEF_RVV_TYPE (vuint32m1_t, 16, __rvv_uint32m1_t, unsigned_int32, VNx2SI, VNx1SI) +DEF_RVV_TYPE (vint32m1_t, 15, __rvv_int32m1_t, int32, VNx2SI, VNx1SI, _i32m1, + _i32, _e32m1) +DEF_RVV_TYPE (vuint32m1_t, 16, __rvv_uint32m1_t, unsigned_int32, VNx2SI, VNx1SI, + _u32m1, _u32, _e32m1) /* LMUL = 2: Machine mode = VNx4SImode when TARGET_MIN_VLEN > 32. Machine mode = VNx2SImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint32m2_t, 15, __rvv_int32m2_t, int32, VNx4SI, VNx2SI) -DEF_RVV_TYPE (vuint32m2_t, 16, __rvv_uint32m2_t, unsigned_int32, VNx4SI, VNx2SI) +DEF_RVV_TYPE (vint32m2_t, 15, __rvv_int32m2_t, int32, VNx4SI, VNx2SI, _i32m2, + _i32, _e32m2) +DEF_RVV_TYPE (vuint32m2_t, 16, __rvv_uint32m2_t, unsigned_int32, VNx4SI, VNx2SI, + _u32m2, _u32, _e32m2) /* LMUL = 4: Machine mode = VNx8SImode when TARGET_MIN_VLEN > 32. Machine mode = VNx4SImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint32m4_t, 15, __rvv_int32m4_t, int32, VNx8SI, VNx4SI) -DEF_RVV_TYPE (vuint32m4_t, 16, __rvv_uint32m4_t, unsigned_int32, VNx8SI, VNx4SI) +DEF_RVV_TYPE (vint32m4_t, 15, __rvv_int32m4_t, int32, VNx8SI, VNx4SI, _i32m4, + _i32, _e32m4) +DEF_RVV_TYPE (vuint32m4_t, 16, __rvv_uint32m4_t, unsigned_int32, VNx8SI, VNx4SI, + _u32m4, _u32, _e32m4) /* LMUL = 8: Machine mode = VNx16SImode when TARGET_MIN_VLEN > 32. Machine mode = VNx8SImode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vint32m8_t, 15, __rvv_int32m8_t, int32, VNx16SI, VNx8SI) +DEF_RVV_TYPE (vint32m8_t, 15, __rvv_int32m8_t, int32, VNx16SI, VNx8SI, _i32m8, + _i32, _e32m8) DEF_RVV_TYPE (vuint32m8_t, 16, __rvv_uint32m8_t, unsigned_int32, VNx16SI, - VNx8SI) + VNx8SI, _u32m8, _u32, _e32m8) /* SEW = 64: Disable when TARGET_MIN_VLEN > 32. */ -DEF_RVV_TYPE (vint64m1_t, 15, __rvv_int64m1_t, intDI, VNx1DI, VOID) -DEF_RVV_TYPE (vuint64m1_t, 16, __rvv_uint64m1_t, unsigned_intDI, VNx1DI, VOID) -DEF_RVV_TYPE (vint64m2_t, 15, __rvv_int64m2_t, intDI, VNx2DI, VOID) -DEF_RVV_TYPE (vuint64m2_t, 16, __rvv_uint64m2_t, unsigned_intDI, VNx2DI, VOID) -DEF_RVV_TYPE (vint64m4_t, 15, __rvv_int64m4_t, intDI, VNx4DI, VOID) -DEF_RVV_TYPE (vuint64m4_t, 16, __rvv_uint64m4_t, unsigned_intDI, VNx4DI, VOID) -DEF_RVV_TYPE (vint64m8_t, 15, __rvv_int64m8_t, intDI, VNx8DI, VOID) -DEF_RVV_TYPE (vuint64m8_t, 16, __rvv_uint64m8_t, unsigned_intDI, VNx8DI, VOID) +DEF_RVV_TYPE (vint64m1_t, 15, __rvv_int64m1_t, intDI, VNx1DI, VOID, _i64m1, + _i64, _e64m1) +DEF_RVV_TYPE (vuint64m1_t, 16, __rvv_uint64m1_t, unsigned_intDI, VNx1DI, VOID, + _u64m1, _u64, _e64m1) +DEF_RVV_TYPE (vint64m2_t, 15, __rvv_int64m2_t, intDI, VNx2DI, VOID, _i64m2, + _i64, _e64m2) +DEF_RVV_TYPE (vuint64m2_t, 16, __rvv_uint64m2_t, unsigned_intDI, VNx2DI, VOID, + _u64m2, _u64, _e64m2) +DEF_RVV_TYPE (vint64m4_t, 15, __rvv_int64m4_t, intDI, VNx4DI, VOID, _i64m4, + _i64, _e64m4) +DEF_RVV_TYPE (vuint64m4_t, 16, __rvv_uint64m4_t, unsigned_intDI, VNx4DI, VOID, + _u64m4, _u64, _e64m4) +DEF_RVV_TYPE (vint64m8_t, 15, __rvv_int64m8_t, intDI, VNx8DI, VOID, _i64m8, + _i64, _e64m8) +DEF_RVV_TYPE (vuint64m8_t, 16, __rvv_uint64m8_t, unsigned_intDI, VNx8DI, VOID, + _u64m8, _u64, _e64m8) /* LMUL = 1/2: Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1SFmode. */ -DEF_RVV_TYPE (vfloat32mf2_t, 18, __rvv_float32mf2_t, float, VNx1SF, VOID) +DEF_RVV_TYPE (vfloat32mf2_t, 18, __rvv_float32mf2_t, float, VNx1SF, VOID, + _f32mf2, _f32, _e32mf2) /* LMUL = 1: Machine mode = VNx2SFmode when TARGET_MIN_VLEN > 32. Machine mode = VNx1SFmode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vfloat32m1_t, 17, __rvv_float32m1_t, float, VNx2SF, VNx1SF) +DEF_RVV_TYPE (vfloat32m1_t, 17, __rvv_float32m1_t, float, VNx2SF, VNx1SF, + _f32m1, _f32, _e32m1) /* LMUL = 2: Machine mode = VNx4SFmode when TARGET_MIN_VLEN > 32. Machine mode = VNx2SFmode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vfloat32m2_t, 17, __rvv_float32m2_t, float, VNx4SF, VNx2SF) +DEF_RVV_TYPE (vfloat32m2_t, 17, __rvv_float32m2_t, float, VNx4SF, VNx2SF, + _f32m2, _f32, _e32m2) /* LMUL = 4: Machine mode = VNx8SFmode when TARGET_MIN_VLEN > 32. Machine mode = VNx4SFmode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vfloat32m4_t, 17, __rvv_float32m4_t, float, VNx8SF, VNx4SF) +DEF_RVV_TYPE (vfloat32m4_t, 17, __rvv_float32m4_t, float, VNx8SF, VNx4SF, + _f32m4, _f32, _e32m4) /* LMUL = 8: Machine mode = VNx16SFmode when TARGET_MIN_VLEN > 32. Machine mode = VNx8SFmode when TARGET_MIN_VLEN = 32. */ -DEF_RVV_TYPE (vfloat32m8_t, 17, __rvv_float32m8_t, float, VNx16SF, VNx8SF) +DEF_RVV_TYPE (vfloat32m8_t, 17, __rvv_float32m8_t, float, VNx16SF, VNx8SF, + _f32m8, _f32, _e32m8) /* SEW = 64: Disable when TARGET_VECTOR_FP64. */ -DEF_RVV_TYPE (vfloat64m1_t, 17, __rvv_float64m1_t, double, VNx1DF, VOID) -DEF_RVV_TYPE (vfloat64m2_t, 17, __rvv_float64m2_t, double, VNx2DF, VOID) -DEF_RVV_TYPE (vfloat64m4_t, 17, __rvv_float64m4_t, double, VNx4DF, VOID) -DEF_RVV_TYPE (vfloat64m8_t, 17, __rvv_float64m8_t, double, VNx8DF, VOID) +DEF_RVV_TYPE (vfloat64m1_t, 17, __rvv_float64m1_t, double, VNx1DF, VOID, _f64m1, + _f64, _e64m1) +DEF_RVV_TYPE (vfloat64m2_t, 17, __rvv_float64m2_t, double, VNx2DF, VOID, _f64m2, + _f64, _e64m2) +DEF_RVV_TYPE (vfloat64m4_t, 17, __rvv_float64m4_t, double, VNx4DF, VOID, _f64m4, + _f64, _e64m4) +DEF_RVV_TYPE (vfloat64m8_t, 17, __rvv_float64m8_t, double, VNx8DF, VOID, _f64m8, + _f64, _e64m8) + +DEF_RVV_OP_TYPE (vv) +DEF_RVV_OP_TYPE (vx) +DEF_RVV_OP_TYPE (v) +DEF_RVV_OP_TYPE (wv) +DEF_RVV_OP_TYPE (wx) +DEF_RVV_OP_TYPE (x_x_v) +DEF_RVV_OP_TYPE (vf2) +DEF_RVV_OP_TYPE (vf4) +DEF_RVV_OP_TYPE (vf8) +DEF_RVV_OP_TYPE (vvm) +DEF_RVV_OP_TYPE (vxm) +DEF_RVV_OP_TYPE (x_x_w) +DEF_RVV_OP_TYPE (v_v) +DEF_RVV_OP_TYPE (v_x) +DEF_RVV_OP_TYPE (vs) +DEF_RVV_OP_TYPE (mm) +DEF_RVV_OP_TYPE (m) +DEF_RVV_OP_TYPE (vf) +DEF_RVV_OP_TYPE (vm) +DEF_RVV_OP_TYPE (wf) +DEF_RVV_OP_TYPE (vfm) +DEF_RVV_OP_TYPE (v_f) + +DEF_RVV_PRED_TYPE (ta) +DEF_RVV_PRED_TYPE (tu) +DEF_RVV_PRED_TYPE (ma) +DEF_RVV_PRED_TYPE (mu) +DEF_RVV_PRED_TYPE (tama) +DEF_RVV_PRED_TYPE (tamu) +DEF_RVV_PRED_TYPE (tuma) +DEF_RVV_PRED_TYPE (tumu) +DEF_RVV_PRED_TYPE (m) +DEF_RVV_PRED_TYPE (tam) +DEF_RVV_PRED_TYPE (tum) +#undef DEF_RVV_PRED_TYPE +#undef DEF_RVV_OP_TYPE #undef DEF_RVV_TYPE diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h index ea67da9905c..425da12326c 100644 --- a/gcc/config/riscv/riscv-vector-builtins.h +++ b/gcc/config/riscv/riscv-vector-builtins.h @@ -21,8 +21,101 @@ #ifndef GCC_RISCV_VECTOR_BUILTINS_H #define GCC_RISCV_VECTOR_BUILTINS_H +/* The full name of an RVV intrinsic function is the concatenation of: + + - the base name ("vadd", etc.) + - the operand suffix ("_vv", "_vx", etc.) + - the type suffix ("_i32m1", "_i32mf2", etc.) + - the predication suffix ("_tamu", "_tumu", etc.) + + Each piece of information is individually useful, so we retain this + classification throughout: + + - function_base represents the base name. + + - operand_type_index can be used as an index to get operand suffix. + + - rvv_op_info can be used as an index to get argument suffix. + + - predication_type_index can be used as an index to get predication suffix. + + In addition to its unique full name, a function may have a shorter + overloaded alias. This alias removes pieces of the suffixes that + can be inferred from the arguments, such as by shortening the mode + suffix or dropping some of the type suffixes. The base name and the + predication suffix stay the same. + + - The function_instance class describes contains all properties of each + individual function. Such these information will be used by + function_builder, function_base, function_shape, gimple_folder, + function_expander, etc. + + - The function_builder class provides several helper function to add an + intrinsic function. + + - The function_shape class describes how that instruction has been presented + at the language level: + + 1. Determine the function name for C and C++ overload function which can + be recognized by compiler at language level for each instruction + according to members of function_instance (base name, operand suffix, + type suffix, predication suffix, etc.). + + 2. Specify the arguments type and return type of each function to + describe how that instruction has presented at language level. + + - The function_base describes how the underlying instruction behaves. + + The static list of functions uses function_group to describe a group + of related functions. The function_builder class is responsible for + expanding this static description into a list of individual functions + and registering the associated built-in functions. function_instance + describes one of these individual functions in terms of the properties + described above. + + The classes involved in compiling a function call are: + + - function_resolver, which resolves an overloaded function call to a + specific function_instance and its associated function decl. + + - function_checker, which checks whether the values of the arguments + conform to the RVV ISA specification. + + - gimple_folder, which tries to fold a function call at the gimple level + + - function_expander, which expands a function call into rtl instructions + + function_resolver and function_checker operate at the language level + and so are associated with the function_shape. gimple_folder and + function_expander are concerned with the behavior of the function + and so are associated with the function_base. */ + namespace riscv_vector { +/* Flags that describe what a function might do, in addition to reading + its arguments and returning a result. */ +static const unsigned int CP_READ_FPCR = 1U << 0; +static const unsigned int CP_RAISE_FP_EXCEPTIONS = 1U << 1; +static const unsigned int CP_READ_MEMORY = 1U << 2; +static const unsigned int CP_WRITE_MEMORY = 1U << 3; +static const unsigned int CP_READ_CSR = 1U << 4; +static const unsigned int CP_WRITE_CSR = 1U << 5; + +/* Bit values used to identify required extensions for RVV intrinsics. */ +#define RVV_REQUIRE_RV64BIT (1 << 0) /* Require RV64. */ +#define RVV_REQUIRE_ZVE64 (1 << 1) /* Require TARGET_MIN_VLEN > 32. */ +#define RVV_REQUIRE_ELEN_FP_32 (1 << 2) /* Require FP ELEN >= 32. */ +#define RVV_REQUIRE_ELEN_FP_64 (1 << 3) /* Require FP ELEN >= 64. */ + +/* Enumerates the RVV operand types. */ +enum operand_type_index +{ + OP_TYPE_none, +#define DEF_RVV_OP_TYPE(NAME) OP_TYPE_##NAME, +#include "riscv-vector-builtins.def" + NUM_OP_TYPES +}; + /* Enumerates the RVV types, together called "vector types" for brevity. */ enum vector_type_index @@ -32,6 +125,31 @@ enum vector_type_index NUM_VECTOR_TYPES }; +/* Enumerates the RVV governing predication types. */ +enum predication_type_index +{ + PRED_TYPE_none, +#define DEF_RVV_PRED_TYPE(NAME) PRED_TYPE_##NAME, +#include "riscv-vector-builtins.def" + NUM_PRED_TYPES +}; + +/* Enumerates the RVV base types. */ +enum rvv_base_type +{ + RVV_BASE_vector, + RVV_BASE_scalar, + RVV_BASE_vector_ptr, + RVV_BASE_scalar_ptr, + RVV_BASE_scalar_const_ptr, + RVV_BASE_void, + RVV_BASE_size, + RVV_BASE_ptrdiff, + RVV_BASE_unsigned_long, + RVV_BASE_long, + NUM_BASE_TYPES +}; + /* Builtin types that are used to register RVV intrinsics. */ struct GTY (()) rvv_builtin_types_t { @@ -42,6 +160,251 @@ struct GTY (()) rvv_builtin_types_t tree scalar_const_ptr; }; +/* Builtin suffix that are used to register RVV intrinsics. */ +struct rvv_builtin_suffixes +{ + const char *vector; + const char *scalar; + const char *vsetvl; +}; + +/* RVV Builtin argument information. */ +struct rvv_arg_type_info +{ + CONSTEXPR rvv_arg_type_info (rvv_base_type base_type_in) + : base_type (base_type_in) + {} + enum rvv_base_type base_type; + + tree get_tree_type (vector_type_index) const; +}; + +/* Static information for each operand. */ +struct rvv_type_info +{ + enum vector_type_index index; + uint64_t required_extensions; +}; + +/* RVV Builtin operands information. */ +struct rvv_op_info +{ + const rvv_type_info *types; + const operand_type_index op; + rvv_arg_type_info ret; + const rvv_arg_type_info *args; +}; + +class registered_function; +class function_base; +class function_shape; + +/* Static information about a set of functions. */ +struct function_group_info +{ + /* The base name, as a string. */ + const char *base_name; + + /* Describes the behavior associated with the function base name. */ + const function_base *const *base; + + /* The shape of the functions, as described above the class definition. + It's possible to have entries with the same base name but different + shapes. */ + const function_shape *const *shape; + + /* A list of the available operand types, predication types, + and of the available operand datatype. + The function supports every combination of the two. + The list of predication is terminated by two NUM_PRED_TYPES, + while the list of operand info is terminated by NUM_BASE_TYPES. + The list of these type suffix is lexicographically ordered based + on the index value. */ + const predication_type_index *preds; + const rvv_op_info ops_infos; +}; + +class GTY ((user)) function_instance +{ +public: + function_instance (const char *, const function_base *, + const function_shape *, rvv_type_info, + predication_type_index, const rvv_op_info *); + + bool operator== (const function_instance &) const; + bool operator!= (const function_instance &) const; + hashval_t hash () const; + + unsigned int call_properties () const; + bool reads_global_state_p () const; + bool modifies_global_state_p () const; + bool could_trap_p () const; + + /* Return true if return type or arguments are floating point type. */ + bool any_type_float_p () const; + + tree get_return_type () const; + tree get_arg_type (unsigned opno) const; + + /* The properties of the function. (The explicit "enum"s are required + for gengtype.) */ + const char *base_name; + const function_base *base; + const function_shape *shape; + rvv_type_info type; + enum predication_type_index pred; + const rvv_op_info *op_info; +}; + +/* A class for building and registering function decls. */ +class function_builder +{ +public: + function_builder (); + ~function_builder (); + + void allocate_argument_types (const function_instance &, vec &) const; + void add_unique_function (const function_instance &, const function_shape *, + tree, vec &); + void register_function_group (const function_group_info &); + void append_name (const char *); + char *finish_name (); + +private: + tree get_attributes (const function_instance &); + + registered_function &add_function (const function_instance &, const char *, + tree, tree, bool); + + /* True if we should create a separate decl for each instance of an + overloaded function, instead of using function_builder. */ + bool m_direct_overloads; + + /* Used for building up function names. */ + obstack m_string_obstack; +}; + +/* A base class for handling calls to built-in functions. */ +class function_call_info : public function_instance +{ +public: + function_call_info (location_t, const function_instance &, tree); + + bool function_returns_void_p (); + + /* The location of the call. */ + location_t location; + + /* The FUNCTION_DECL that is being called. */ + tree fndecl; +}; + +/* Return true if the function has no return value. */ +inline bool +function_call_info::function_returns_void_p () +{ + return TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; +} + +/* A class for expanding a function call into RTL. */ +class function_expander : public function_call_info +{ +public: + function_expander (const function_instance &, tree, tree, rtx); + rtx expand (); + + void add_input_operand (machine_mode, rtx); + void add_input_operand (unsigned argno); + rtx generate_insn (insn_code); + + /* The function call expression. */ + tree exp; + + /* For functions that return a value, this is the preferred location + of that value. It could be null or could have a different mode + from the function return type. */ + rtx target; + + /* The number of the operands. */ + int opno; + +private: + /* Used to build up the operands to an instruction. */ + struct expand_operand m_ops[MAX_RECOG_OPERANDS]; +}; + +/* Provides information about a particular function base name, and handles + tasks related to the base name. */ +class function_base +{ +public: + /* Return a set of CP_* flags that describe what the function might do, + in addition to reading its arguments and returning a result. */ + virtual unsigned int call_properties (const function_instance &) const; + + /* Expand the given call into rtl. Return the result of the function, + or an arbitrary value if the function doesn't return a result. */ + virtual rtx expand (function_expander &) const = 0; +}; + +/* Classifies functions into "shapes" base on: + + - Base name of the intrinsic function. + + - Operand types list. + + - Argument type list. + + - Predication type list. */ +class function_shape +{ +public: + /* Shape the function name according to function_instance. */ + virtual char *get_name (function_builder &, const function_instance &, + bool) const + = 0; + + /* Define all functions associated with the given group. */ + virtual void build (function_builder &, const function_group_info &) const + = 0; +}; + +extern const char *const operand_suffixes[NUM_OP_TYPES]; +extern const rvv_builtin_suffixes type_suffixes[NUM_VECTOR_TYPES + 1]; +extern const char *const predication_suffixes[NUM_PRED_TYPES]; +extern rvv_builtin_types_t builtin_types[NUM_VECTOR_TYPES + 1]; + +inline bool +function_instance::operator!= (const function_instance &other) const +{ + return !operator== (other); +} + +/* Expand the call and return its lhs. */ +inline rtx +function_expander::expand () +{ + return base->expand (*this); +} + +/* Create op and add it into M_OPS and increase OPNO. */ +inline void +function_expander::add_input_operand (machine_mode mode, rtx op) +{ + create_input_operand (&m_ops[opno++], op, mode); +} + +/* Default implementation of function_base::call_properties, with conservatively + correct behavior for floating-point instructions. */ +inline unsigned int +function_base::call_properties (const function_instance &instance) const +{ + unsigned int flags = 0; + if (instance.any_type_float_p ()) + return flags | CP_READ_FPCR | CP_RAISE_FP_EXCEPTIONS; + return flags; +} + } // end namespace riscv_vector #endif