/* function_shape implementation for RISC-V 'V' Extension for GNU compiler. Copyright (C) 2022-2024 Free Software Foundation, Inc. Contributed by Ju-Zhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd. 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 "tree.h" #include "rtl.h" #include "tm_p.h" #include "memmodel.h" #include "insn-codes.h" #include "optabs.h" #include "riscv-vector-builtins.h" #include "riscv-vector-builtins-shapes.h" namespace riscv_vector { /* Check whether the RETURN_TYPE and ARGUMENT_TYPES are valid for the function. */ static bool check_type (tree return_type, vec &argument_types) { tree arg; unsigned i; if (!return_type) return false; FOR_EACH_VEC_ELT (argument_types, i, arg) if (!arg) return false; return true; } /* Add one function instance for GROUP, using operand suffix at index OI, mode suffix at index PAIR && bi and predication suffix at index pred_idx. */ static void build_one (function_builder &b, const function_group_info &group, unsigned int pred_idx, unsigned int vec_type_idx) { /* Byte forms of non-tuple vlxusegei take 21 arguments. */ auto_vec argument_types; function_instance function_instance (group.base_name, *group.base, *group.shape, group.ops_infos.types[vec_type_idx], group.preds[pred_idx], &group.ops_infos); tree return_type = group.ops_infos.ret.get_tree_type ( group.ops_infos.types[vec_type_idx].index); b.allocate_argument_types (function_instance, argument_types); b.apply_predication (function_instance, return_type, argument_types); if (TARGET_XTHEADVECTOR && !check_type (return_type, argument_types)) return; b.add_overloaded_function (function_instance, *group.shape, group.required_extensions); b.add_unique_function (function_instance, (*group.shape), return_type, argument_types, group.required_extensions); } /* Determine whether the intrinsic supports the currently processed vector type */ static bool supports_vectype_p (const function_group_info &group, unsigned int vec_type_idx) { int index = group.ops_infos.types[vec_type_idx].index; if (index < VECTOR_TYPE_vbfloat16mf4_t || index > VECTOR_TYPE_vbfloat16m8_t) return true; /* Only judge for bf16 vector type */ if (*group.shape == shapes::loadstore || *group.shape == shapes::indexed_loadstore || *group.shape == shapes::vundefined || *group.shape == shapes::misc || *group.shape == shapes::vset || *group.shape == shapes::vget || *group.shape == shapes::vcreate || *group.shape == shapes::fault_load || *group.shape == shapes::seg_loadstore || *group.shape == shapes::seg_indexed_loadstore || *group.shape == shapes::seg_fault_load) return true; return false; } /* Add a function instance for every operand && predicate && args combination in GROUP. Take the function base name from GROUP && operand suffix from operand_suffixes && mode suffix from type_suffixes && predication suffix from predication_suffixes. Use apply_predication to add in the predicate. */ static void build_all (function_builder &b, const function_group_info &group) { for (unsigned int pred_idx = 0; group.preds[pred_idx] != NUM_PRED_TYPES; ++pred_idx) for (unsigned int vec_type_idx = 0; group.ops_infos.types[vec_type_idx].index != NUM_VECTOR_TYPES; ++vec_type_idx) { if (supports_vectype_p (group, vec_type_idx)) build_one (b, group, pred_idx, vec_type_idx); } } /* Declare the function shape NAME, pointing it to an instance of class _def. */ #define SHAPE(DEF, VAR) \ static CONSTEXPR const DEF##_def VAR##_obj; \ namespace shapes { const function_shape *const VAR = &VAR##_obj; } #define BASE_NAME_MAX_LEN 17 /* Base class for build. */ struct build_base : public function_shape { void build (function_builder &b, const function_group_info &group) const override { build_all (b, group); } }; /* vsetvl_def class. */ struct vsetvl_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* vsetvl* instruction doesn't have C++ overloaded functions. */ if (overloaded_p) return nullptr; b.append_base_name (instance.base_name); b.append_name (type_suffixes[instance.type.index].vsetvl); return b.finish_name (); } }; /* loadstore_def class. */ struct loadstore_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); tree type = builtin_types[instance.type.index].vector; machine_mode mode = TYPE_MODE (type); int sew = GET_MODE_BITSIZE (GET_MODE_INNER (mode)); /* vop --> vop. */ if (GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL) b.append_sew (sew); /* vop_v --> vop_v_. */ if (!overloaded_p) { /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* indexed_loadstore_def class. */ struct indexed_loadstore_def : public function_shape { void build (function_builder &b, const function_group_info &group) const override { for (unsigned int pred_idx = 0; group.preds[pred_idx] != NUM_PRED_TYPES; ++pred_idx) { for (unsigned int vec_type_idx = 0; group.ops_infos.types[vec_type_idx].index != NUM_VECTOR_TYPES; ++vec_type_idx) { tree index_type = group.ops_infos.args[1].get_tree_type ( group.ops_infos.types[vec_type_idx].index); if (!index_type) continue; build_one (b, group, pred_idx, vec_type_idx); } } } char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); /* vop_v --> vop_v_. */ if (!overloaded_p) { /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* Add one function instance for GROUP, using operand suffix at index OI, mode suffix at index PAIR && bi and predication suffix at index pred_idx. */ static void build_th_loadstore (function_builder &b, const function_group_info &group, unsigned int pred_idx, unsigned int vec_type_idx) { auto_vec argument_types; function_instance function_instance (group.base_name, *group.base, *group.shape, group.ops_infos.types[vec_type_idx], group.preds[pred_idx], &group.ops_infos); tree return_type = group.ops_infos.ret.get_tree_type ( group.ops_infos.types[vec_type_idx].index); b.allocate_argument_types (function_instance, argument_types); b.apply_predication (function_instance, return_type, argument_types); if (TARGET_XTHEADVECTOR && !check_type (return_type, argument_types)) return; tree type = builtin_types[group.ops_infos.types[vec_type_idx].index].vector; if (strstr (group.base_name, "l") && strstr (group.base_name, "u") && !TYPE_UNSIGNED (TREE_TYPE (type))) return; if (strstr (group.base_name, "l") && !strstr (group.base_name, "u") && TYPE_UNSIGNED (TREE_TYPE (type))) return; machine_mode mode = TYPE_MODE (type); int sew = GET_MODE_BITSIZE (GET_MODE_INNER (mode)); if (strstr (group.base_name, "h") && sew == 8) return; if (strstr (group.base_name, "w") && (sew == 8 || sew ==16)) return; b.add_overloaded_function (function_instance, *group.shape, group.required_extensions); b.add_unique_function (function_instance, (*group.shape), return_type, argument_types, group.required_extensions); } /* th_loadstore_width_def class. */ struct th_loadstore_width_def : public build_base { void build (function_builder &b, const function_group_info &group) const override { for (unsigned int pred_idx = 0; group.preds[pred_idx] != NUM_PRED_TYPES; ++pred_idx) { for (unsigned int vec_type_idx = 0; group.ops_infos.types[vec_type_idx].index != NUM_VECTOR_TYPES; ++vec_type_idx) { build_th_loadstore (b, group, pred_idx, vec_type_idx); } } } char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_name ("__riscv_th_"); b.append_name (instance.base_name); /* vop_v --> vop_v_. */ if (!overloaded_p) { /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* th_indexed_loadstore_width_def class. */ struct th_indexed_loadstore_width_def : public function_shape { void build (function_builder &b, const function_group_info &group) const override { for (unsigned int pred_idx = 0; group.preds[pred_idx] != NUM_PRED_TYPES; ++pred_idx) { for (unsigned int vec_type_idx = 0; group.ops_infos.types[vec_type_idx].index != NUM_VECTOR_TYPES; ++vec_type_idx) { tree index_type = group.ops_infos.args[1].get_tree_type ( group.ops_infos.types[vec_type_idx].index); if (!index_type) continue; build_th_loadstore (b, group, pred_idx, vec_type_idx); } } } char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_name ("__riscv_th_"); b.append_name (instance.base_name); /* vop_v --> vop_v_. */ if (!overloaded_p) { /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* alu_def class. */ struct alu_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); /* vop_ --> vop__. */ if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } bool check (function_checker &c) const override { /* Check whether rounding mode argument is a valid immediate. */ if (c.base->has_rounding_mode_operand_p ()) { /* Some invalid overload intrinsic like below will have zero for c.arg_num (). Thus, make sure arg_num is big enough here. __riscv_vaadd () will make c.arg_num () == 0. */ if (!c.any_type_float_p () && c.arg_num () >= 2) return c.require_immediate (c.arg_num () - 2, VXRM_RNU, VXRM_ROD); /* TODO: We will support floating-point intrinsic modeling rounding mode in the future. */ } return true; } }; /* The base class for frm build. */ struct build_frm_base : public build_base { /* Normalize vf_frm to vf. */ static void normalize_base_name (char *to, const char *from, int limit) { strncpy (to, from, limit - 1); char *suffix = strstr (to, "_frm"); if (suffix) *suffix = '\0'; to[limit - 1] = '\0'; } bool check (function_checker &c) const override { gcc_assert (c.any_type_float_p ()); /* Check whether rounding mode argument is a valid immediate. Some invalid overload intrinsic like below will have zero for c.arg_num (). Thus, make sure arg_num is big enough here. __riscv_vaadd () will make c.arg_num () == 0. */ if (c.base->has_rounding_mode_operand_p () && c.arg_num () >= 2) { unsigned int frm_num = c.arg_num () - 2; return c.require_immediate (frm_num, FRM_STATIC_MIN, FRM_STATIC_MAX); } return true; } }; /* alu_frm_def class. */ struct alu_frm_def : public build_frm_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { char base_name[BASE_NAME_MAX_LEN] = {}; /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; normalize_base_name (base_name, instance.base_name, sizeof (base_name)); b.append_base_name (base_name); /* vop_ --> vop__. */ if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_rm" suffix for vop_rm C++ overloaded API. */ if (!overloaded_p) b.append_name ("_rm"); /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* widen_alu_frm_def class. */ struct widen_alu_frm_def : public build_frm_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { char base_name[BASE_NAME_MAX_LEN] = {}; normalize_base_name (base_name, instance.base_name, sizeof (base_name)); b.append_base_name (base_name); /* vop --> vop_. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop__. */ if (!overloaded_p) b.append_name (type_suffixes[instance.type.index].vector); /* According to rvv-intrinsic-doc, it does not add "_rm" suffix for vop_rm C++ overloaded API. */ if (!overloaded_p) b.append_name ("_rm"); /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* narrow_alu_frm_def class. */ struct narrow_alu_frm_def : public build_frm_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { char base_name[BASE_NAME_MAX_LEN] = {}; normalize_base_name (base_name, instance.base_name, sizeof (base_name)); b.append_base_name (base_name); if (!overloaded_p) { /* vop --> vop_. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop__. */ vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } /* According to rvv-intrinsic-doc, it does not add "_rm" suffix for vop_rm C++ overloaded API. */ if (!overloaded_p) b.append_name ("_rm"); /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* reduc_alu_frm_def class. */ struct reduc_alu_frm_def : public build_frm_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { char base_name[BASE_NAME_MAX_LEN] = {}; normalize_base_name (base_name, instance.base_name, sizeof (base_name)); b.append_base_name (base_name); /* vop_ --> vop__. */ if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } /* According to rvv-intrinsic-doc, it does not add "_rm" suffix for vop_rm C++ overloaded API. */ if (!overloaded_p) b.append_name ("_rm"); /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* widen_alu_def class. Handle vwadd/vwsub. Unlike vadd.vx/vadd.vv/vwmul.vv/vwmul.vx, vwadd.vv/vwadd.vx/vwadd.wv/vwadd.wx has 'OP' suffix in overloaded API. */ struct widen_alu_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); /* vop --> vop_. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop__. */ if (!overloaded_p) b.append_name (type_suffixes[instance.type.index].vector); /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* no_mask_policy_def class. Such instructions belong to this class doesn't need mask policy. */ struct no_mask_policy_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (!overloaded_p) b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop__. */ if (!overloaded_p) b.append_name (type_suffixes[instance.type.index].vector); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* return_mask_def class. Such instructions belong to this class is returning mask value. */ struct return_mask_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (!overloaded_p) b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop___. */ if (!overloaded_p) { b.append_name (type_suffixes[instance.type.index].vector); vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* narrow_alu_def class. Handle narrowing instructions like vnsrl.wv. */ struct narrow_alu_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (!overloaded_p) { /* vop --> vop_. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop__. */ vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } bool check (function_checker &c) const override { /* Check whether rounding mode argument is a valid immediate. */ if (c.base->has_rounding_mode_operand_p ()) { /* Some invalid overload intrinsic like below will have zero for c.arg_num (). Thus, make sure arg_num is big enough here. __riscv_vaadd () will make c.arg_num () == 0. */ if (!c.any_type_float_p () && c.arg_num () >= 2) return c.require_immediate (c.arg_num () - 2, VXRM_RNU, VXRM_ROD); /* TODO: We will support floating-point intrinsic modeling rounding mode in the future. */ } return true; } }; /* move_def class. Handle vmv.v.v/vmv.v.x. */ struct move_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* vmv.v.x/vfmv.v.f (PRED_none) can not be overloaded. */ if ((instance.op_info->op == OP_TYPE_x || instance.op_info->op == OP_TYPE_f) && overloaded_p && instance.pred == PRED_TYPE_none) return nullptr; b.append_base_name (instance.base_name); if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* mask_alu_def class. */ struct mask_alu_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); if (instance.op_info->op == OP_TYPE_mm || instance.op_info->op == OP_TYPE_m) if (!overloaded_p) b.append_name (operand_suffixes[instance.op_info->op]); /* vop_ --> vop__. */ if (!overloaded_p) b.append_name (type_suffixes[instance.type.index].vector); /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* reduc_alu_def class. */ struct reduc_alu_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); /* vop_ --> vop__. */ if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* th_extract_def class. */ struct th_extract_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_name ("__riscv_th_"); b.append_name (instance.base_name); if (overloaded_p) return b.finish_name (); b.append_name (type_suffixes[instance.type.index].vector); b.append_name (type_suffixes[instance.type.index].scalar); return b.finish_name (); } }; /* scalar_move_def class. */ struct scalar_move_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (overloaded_p) return b.finish_name (); b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); b.append_name (type_suffixes[instance.type.index].scalar); return b.finish_name (); } }; /* vundefined_def class. */ struct vundefined_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { if (overloaded_p) return nullptr; b.append_base_name (instance.base_name); b.append_name (type_suffixes[instance.type.index].vector); return b.finish_name (); } }; /* misc_def class. */ struct misc_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); vector_type_index arg0_type_idx = instance.op_info->args[0].get_function_type_index ( instance.type.index); b.append_name (type_suffixes[arg0_type_idx].vector); } vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); return b.finish_name (); } }; /* vset_def class. */ struct vset_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); vector_type_index arg_type_idx = instance.op_info->args[2].get_function_type_index ( instance.type.index); b.append_name (type_suffixes[arg_type_idx].vector); vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } return b.finish_name (); } bool check (function_checker &c) const override { poly_int64 outer_size = GET_MODE_SIZE (c.arg_mode (0)); poly_int64 inner_size = GET_MODE_SIZE (c.arg_mode (2)); unsigned int nvecs = exact_div (outer_size, inner_size).to_constant (); return c.require_immediate (1, 0, nvecs - 1); } }; /* vget_def class. */ struct vget_def : public misc_def { bool check (function_checker &c) const override { poly_int64 outer_size = GET_MODE_SIZE (c.arg_mode (0)); poly_int64 inner_size = GET_MODE_SIZE (c.ret_mode ()); unsigned int nvecs = exact_div (outer_size, inner_size).to_constant (); return c.require_immediate (1, 0, nvecs - 1); } }; /* vcreate_def class. */ struct vcreate_def : public build_base { void build (function_builder &b, const function_group_info &group) const override { for (unsigned int vec_type_idx = 0; group.ops_infos.types[vec_type_idx].index != NUM_VECTOR_TYPES; ++vec_type_idx) { auto_vec argument_types; function_instance function_instance (group.base_name, *group.base, *group.shape, group.ops_infos.types[vec_type_idx], group.preds[0], &group.ops_infos); tree return_type = group.ops_infos.ret.get_tree_type ( group.ops_infos.types[vec_type_idx].index); if (!return_type) continue; tree arg_type = function_instance.op_info->args[0].get_tree_type ( function_instance.type.index); machine_mode outer_mode = TYPE_MODE (return_type); machine_mode inner_mode = TYPE_MODE (arg_type); unsigned int nargs = exact_div (GET_MODE_SIZE (outer_mode), GET_MODE_SIZE (inner_mode)) .to_constant (); for (unsigned int i = 0; i < nargs; i++) argument_types.quick_push (arg_type); b.add_unique_function (function_instance, (*group.shape), return_type, argument_types, group.required_extensions); } } char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { if (overloaded_p) return nullptr; b.append_base_name (instance.base_name); b.append_name (operand_suffixes[instance.op_info->op]); if (instance.op_info->ret.base_type != RVV_BASE_vector) { vector_type_index arg_type_idx = instance.op_info->args[0].get_function_type_index ( instance.type.index); b.append_name (type_suffixes[arg_type_idx].vector); } vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); return b.finish_name (); } }; /* read_vl_def class. */ struct read_vl_def : public function_shape { void build (function_builder &b, const function_group_info &group) const override { auto_vec argument_types; b.add_unique_function (get_read_vl_instance (), (*group.shape), size_type_node, argument_types, group.required_extensions); } char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { if (overloaded_p) return nullptr; b.append_base_name (instance.base_name); return b.finish_name (); } }; /* fault_load_def class. */ struct fault_load_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; tree type = builtin_types[instance.type.index].vector; machine_mode mode = TYPE_MODE (type); int sew = GET_MODE_BITSIZE (GET_MODE_INNER (mode)); b.append_name ("__riscv_"); b.append_name ("vle"); b.append_sew (sew); b.append_name ("ff"); /* vop_v --> vop_v_. */ if (!overloaded_p) { /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* vlenb_def class. */ struct vlenb_def : public function_shape { void build (function_builder &b, const function_group_info &group) const override { auto_vec argument_types; function_instance function_instance (group.base_name, *group.base, *group.shape, group.ops_infos.types[0], group.preds[0], &group.ops_infos); b.add_unique_function (function_instance, (*group.shape), long_unsigned_type_node, argument_types, group.required_extensions); } char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { if (overloaded_p) return nullptr; b.append_base_name (instance.base_name); return b.finish_name (); } }; /* seg_loadstore_def class. */ struct seg_loadstore_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); tree type = builtin_types[instance.type.index].vector; machine_mode mode = TYPE_MODE (type); int nf = get_nf (mode); /* vop --> vop. */ b.append_nf (nf); /* vop --> vope. */ b.append_name ("e"); int sew = GET_MODE_BITSIZE (GET_MODE_INNER (mode)); /* vope --> vope. */ b.append_sew (sew); if (!overloaded_p) { /* vope --> vope_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vope_v --> vope_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* seg_indexed_loadstore_def class. */ struct seg_indexed_loadstore_def : public indexed_loadstore_def { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); tree type = builtin_types[instance.type.index].vector; machine_mode mode = TYPE_MODE (type); int nf = get_nf (mode); /* vop --> vop. */ b.append_nf (nf); /* vop --> vopei. */ b.append_name ("ei"); /* vopei --> vopei. */ vector_type_index arg1_type_idx = instance.op_info->args[1].get_function_type_index (instance.type.index); tree index_type = builtin_types[arg1_type_idx].vector; machine_mode index_mode = TYPE_MODE (index_type); int eew = GET_MODE_BITSIZE (GET_MODE_INNER (index_mode)); b.append_sew (eew); if (!overloaded_p) { /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* seg_fault_load_def class. */ struct seg_fault_load_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_name ("__riscv_vlseg"); tree type = builtin_types[instance.type.index].vector; machine_mode mode = TYPE_MODE (type); int nf = get_nf (mode); /* vop --> vop. */ b.append_nf (nf); /* vop --> vope. */ b.append_name ("e"); int sew = GET_MODE_BITSIZE (GET_MODE_INNER (mode)); /* vope --> vope. */ b.append_sew (sew); /* vope --> vopeff. */ b.append_name ("ff"); if (!overloaded_p) { /* vopeff --> vopeff_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* vopeff_v --> vopeff_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to rvv-intrinsic-doc, it does not add "_m" suffix for vop_m C++ overloaded API. */ if (overloaded_p && instance.pred == PRED_TYPE_m) return b.finish_name (); b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* vsm4r/vaes* class. */ struct crypto_vv_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); b.append_name (operand_suffixes[instance.op_info->op]); if (!overloaded_p) { if (instance.op_info->op == OP_TYPE_vv) b.append_name (type_suffixes[instance.type.index].vector); else { vector_type_index arg0_type_idx = instance.op_info->args[1].get_function_type_index (instance.type.index); b.append_name (type_suffixes[arg0_type_idx].vector); vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } } b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* vaeskf1/vaeskf2/vsm4k/vsm3c class. */ struct crypto_vi_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); b.append_name (type_suffixes[instance.type.index].vector); } b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* vaesz class. */ struct crypto_vv_no_op_type_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return nullptr; b.append_base_name (instance.base_name); if (!overloaded_p) { b.append_name (operand_suffixes[instance.op_info->op]); vector_type_index arg0_type_idx = instance.op_info->args[1].get_function_type_index (instance.type.index); b.append_name (type_suffixes[arg0_type_idx].vector); vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); b.append_name (type_suffixes[ret_type_idx].vector); } b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* sf_vqmacc_def class. */ struct sf_vqmacc_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); /* vop --> vop_v. */ b.append_name (operand_suffixes[instance.op_info->op]); /* Return nullptr if it can not be overloaded. */ if (overloaded_p && !instance.base->can_be_overloaded_p (instance.pred)) return b.finish_name (); if (!overloaded_p) { /* vop_v --> vop_v_. */ b.append_name (type_suffixes[instance.type.index].vector); } /* According to SIFIVE vector-intrinsic-doc, it adds "_tu" suffix for vop_m C++ overloaded API.*/ b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; /* sf_vfnrclip_def class. Handle instructions like vfnrclip. */ struct sf_vfnrclip_def : public build_base { char *get_name (function_builder &b, const function_instance &instance, bool overloaded_p) const override { b.append_base_name (instance.base_name); if (overloaded_p && (!instance.base->can_be_overloaded_p (instance.pred) || instance.pred == PRED_TYPE_m)) return b.finish_name (); if (!overloaded_p) { vector_type_index ret_type_idx = instance.op_info->ret.get_function_type_index (instance.type.index); /* v --> v_. */ b.append_name (type_suffixes[ret_type_idx].vector); } /* According to SIFIVE vector-intrinsic-doc, it adds "_m\_tu\ _tum\_tumu\_mu" suffixes for vop_m C++ overloaded API.*/ b.append_name (predication_suffixes[instance.pred]); return b.finish_name (); } }; SHAPE(vsetvl, vsetvl) SHAPE(vsetvl, vsetvlmax) SHAPE(loadstore, loadstore) SHAPE(indexed_loadstore, indexed_loadstore) SHAPE(th_loadstore_width, th_loadstore_width) SHAPE(th_indexed_loadstore_width, th_indexed_loadstore_width) SHAPE(alu, alu) SHAPE(alu_frm, alu_frm) SHAPE(widen_alu, widen_alu) SHAPE(widen_alu_frm, widen_alu_frm) SHAPE(no_mask_policy, no_mask_policy) SHAPE(return_mask, return_mask) SHAPE(narrow_alu, narrow_alu) SHAPE(narrow_alu_frm, narrow_alu_frm) SHAPE(move, move) SHAPE(mask_alu, mask_alu) SHAPE(reduc_alu, reduc_alu) SHAPE(reduc_alu_frm, reduc_alu_frm) SHAPE(th_extract, th_extract) SHAPE(scalar_move, scalar_move) SHAPE(vundefined, vundefined) SHAPE(misc, misc) SHAPE(vset, vset) SHAPE(vget, vget) SHAPE(vcreate, vcreate) SHAPE(read_vl, read_vl) SHAPE(fault_load, fault_load) SHAPE(vlenb, vlenb) SHAPE(seg_loadstore, seg_loadstore) SHAPE(seg_indexed_loadstore, seg_indexed_loadstore) SHAPE(seg_fault_load, seg_fault_load) SHAPE(crypto_vv, crypto_vv) SHAPE(crypto_vi, crypto_vi) SHAPE(crypto_vv_no_op_type, crypto_vv_no_op_type) SHAPE (sf_vqmacc, sf_vqmacc) SHAPE (sf_vfnrclip, sf_vfnrclip) } // end namespace riscv_vector