From: zhongjuzhe <juzhe.zh...@rivai.ai> gcc/ChangeLog:
* config.gcc: Add riscv-vector-builtins-functions.o and riscv-vector-builtins.o extra_objs for RVV support. * config/riscv/riscv-builtins.cc (riscv_init_builtins): Add RVV support. (riscv_builtin_decl): Add RVV support. (riscv_expand_builtin): Add RVV support. (riscv_gimple_fold_builtin): New function. * config/riscv/riscv-protos.h (riscv_gimple_fold_builtin): New function. (enum riscv_builtin_class): New macro define. * config/riscv/riscv-vector.cc (rvv_get_mask_mode): New function. * config/riscv/riscv-vector.h (rvv_get_mask_mode): New function. * config/riscv/riscv.cc (riscv_class_max_nregs): Add RVV register. (riscv_conditional_register_usage): Add RVV register. (TARGET_GIMPLE_FOLD_BUILTIN): New targethook. * config/riscv/t-riscv: New object. * config/riscv/md-parser: New file. * config/riscv/riscv-vector-builtins-functions.cc: New file. * config/riscv/riscv-vector-builtins-functions.def: New file. * config/riscv/riscv-vector-builtins-functions.h: New file. * config/riscv/riscv-vector-builtins-iterators.def: New file. * config/riscv/riscv-vector-builtins.cc: New file. * config/riscv/riscv-vector-builtins.def: New file. * config/riscv/riscv-vector-builtins.h: New file. * config/riscv/vector-iterators.md: New file. --- gcc/config.gcc | 5 +- gcc/config/riscv/md-parser | 205 ++++ gcc/config/riscv/riscv-builtins.cc | 88 +- gcc/config/riscv/riscv-protos.h | 19 + .../riscv/riscv-vector-builtins-functions.cc | 1012 +++++++++++++++++ .../riscv/riscv-vector-builtins-functions.def | 34 + .../riscv/riscv-vector-builtins-functions.h | 491 ++++++++ .../riscv/riscv-vector-builtins-iterators.def | 12 + gcc/config/riscv/riscv-vector-builtins.cc | 266 +++++ gcc/config/riscv/riscv-vector-builtins.def | 37 + gcc/config/riscv/riscv-vector-builtins.h | 59 + gcc/config/riscv/riscv-vector.cc | 17 + gcc/config/riscv/riscv-vector.h | 1 + gcc/config/riscv/riscv.cc | 21 + gcc/config/riscv/t-riscv | 36 + gcc/config/riscv/vector-iterators.md | 19 + 16 files changed, 2307 insertions(+), 15 deletions(-) create mode 100644 gcc/config/riscv/md-parser create mode 100644 gcc/config/riscv/riscv-vector-builtins-functions.cc create mode 100644 gcc/config/riscv/riscv-vector-builtins-functions.def create mode 100644 gcc/config/riscv/riscv-vector-builtins-functions.h create mode 100644 gcc/config/riscv/riscv-vector-builtins-iterators.def create mode 100644 gcc/config/riscv/riscv-vector-builtins.cc create mode 100644 gcc/config/riscv/riscv-vector-builtins.def create mode 100644 gcc/config/riscv/riscv-vector-builtins.h create mode 100644 gcc/config/riscv/vector-iterators.md diff --git a/gcc/config.gcc b/gcc/config.gcc index 50154c2eb3a..bdda82ae576 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -517,8 +517,11 @@ pru-*-*) ;; riscv*) cpu_type=riscv - extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-vector.o" + extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-vector.o riscv-vector-builtins-functions.o riscv-vector-builtins.o" d_target_objs="riscv-d.o" + target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-builtins.cc \$(srcdir)/config/riscv/riscv-vector-builtins.cc" + target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins-functions.cc" + target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins-functions.h" ;; rs6000*-*-*) extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" diff --git a/gcc/config/riscv/md-parser b/gcc/config/riscv/md-parser new file mode 100644 index 00000000000..311b8709c0a --- /dev/null +++ b/gcc/config/riscv/md-parser @@ -0,0 +1,205 @@ +# Mode iterators and attributes parser for RISC-V 'V' Extension for GNU compiler. +# Copyright (C) 2022-2022 Free Software Foundation, Inc. +# Contributed by Juzhe Zhong (juzhe.zh...@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 +# <http://www.gnu.org/licenses/>. + +import os +import sys + + +def print_err(msg): + print("\033[31m\033[1mRISCV md parser Error: %s\033[0m\033[0m" % msg) + + +def write_to_file(file_path, one_line, opt='a+'): + dir_name = os.path.dirname(file_path) + if dir_name is not None and len(dir_name) > 0: + os.makedirs(dir_name, exist_ok=True) + with open(file_path, opt, encoding="utf-8") as f: + f.write(one_line) + + +def get_prologue(): + return """/* Do not modify this file, it auto gen by md-parser script */ +#ifndef DEF_RISCV_ARG_MODE_ATTR_VARIABLE +#define DEF_RISCV_ARG_MODE_ATTR_VARIABLE(A, B) +#endif + +#ifndef DEF_RISCV_ARG_MODE_ATTR +#define DEF_RISCV_ARG_MODE_ATTR(A, B, C, D, E) +#endif + +""" + + +def get_epilogue(): + return """ +#undef DEF_RISCV_ARG_MODE_ATTR_VARIABLE +#undef DEF_RISCV_ARG_MODE_ATTR +""" + + +def gen_mode_attr(def_seg): + result_str = "" + element_cnt = 0 + for value_seg in def_seg.value_segment_list: + splitted_value_seg_string = value_seg.string.split() + if len(splitted_value_seg_string) == 2: + # we only want the def_seg for intrinsics function code which has the "mode" as right hand side value + attr = splitted_value_seg_string[1] + if not attr.isdigit() and (attr.upper().replace('X', 'x') == attr) and not attr.startswith ("0x"): + result_str += "DEF_RISCV_ARG_MODE_ATTR(%s, %d, %s, %s, %s)\n" % ( + def_seg.name, element_cnt, splitted_value_seg_string[0], attr, "TARGET_FP16" if attr.count("HF") > 0 else "TARGET_HARD_FLOAT" if attr.count("SF") > 0 else "TARGET_DOUBLE_FLOAT" if attr.count("DF") > 0 else "TARGET_ANY") + element_cnt += 1 + else: + # if the mode_attr is not a totally attribute with the "mode" value, ignore the whole pack + return "" + else: + print_err("Value Segment(%s) in \"%s\" maybe not right for \"%s\"" % ( + value_seg.string, def_seg.name, def_seg.def_type)) + if len(result_str) > 0: + result_str = "DEF_RISCV_ARG_MODE_ATTR_VARIABLE(%s, %d)\n%s" % (def_seg.name, element_cnt, result_str) + return result_str + + +def gen_mode_iterator(def_seg): + result_str = "" + element_cnt = 0 + for value_seg in def_seg.value_segment_list: + splitted_value_seg_string = value_seg.string.split() + if len(splitted_value_seg_string) == 1: + result_str += "DEF_RISCV_ARG_MODE_ATTR(%s, %d, %s, %s, TARGET_ANY)\n" % ( + def_seg.name, element_cnt, value_seg.string, value_seg.string) + element_cnt += 1 + elif len(splitted_value_seg_string) == 2: + result_str += "DEF_RISCV_ARG_MODE_ATTR(%s, %d, %s, %s, %s)\n" % ( + def_seg.name, element_cnt, splitted_value_seg_string[0], splitted_value_seg_string[0], + splitted_value_seg_string[1]) + element_cnt += 1 + else: + print_err("Value Segment(%s) in \"%s\" maybe not right for \"%s\"" % ( + value_seg.string, def_seg.name, def_seg.def_type)) + if len(result_str) > 0: + result_str = "DEF_RISCV_ARG_MODE_ATTR_VARIABLE(%s, %d)\n%s" % (def_seg.name, element_cnt, result_str) + return result_str + + +class Segment: + def __init__(self): + self.string = "" + self.parentheses = 0 + + def append(self, char_value): + self.string += char_value + self.parentheses += 1 if char_value == '(' else -1 if char_value == ')' else 0 + + def is_intact(self): + return self.parentheses == 0 + + def strip_self(self): + self.string = self.string.replace('(', '').replace(')', '').replace('"', ' ') + self.string = self.string.strip() + return self + + def __str__(self): + return self.string + + +class DefSegment(Segment): + def __init__(self): + super().__init__() + self.def_type = "" + self.name = "" + self.value_str = "" + self.value_segment_list = [] + + def make_value_segments(self): + # split value string into multiple value segments which will contain a single or a double value array + i = 0 + current_value_segment = None + while i < len(self.value_str): + if self.value_str[i] != ' ' and current_value_segment is None: + # new segment start + current_value_segment = Segment() + current_value_segment.append(self.value_str[i]) + elif current_value_segment is not None: + current_value_segment.append(self.value_str[i]) + if current_value_segment.is_intact() and ( + current_value_segment.string.endswith(' ') or current_value_segment.string.endswith(')')): + self.value_segment_list.append(current_value_segment.strip_self()) + current_value_segment = None + i += 1 + # append the last segment which is missed by the while loop + if current_value_segment is not None: + self.value_segment_list.append(current_value_segment.strip_self()) + + def parse(self): + if len(self.string) == 0: + return False + if self.string.count('[') != 1 or self.string.count(']') != 1: + print_err("\"%s\" is not a valid [...] format string" % self.string) + return False + # ignore the '(' and ')' + self.string = self.string[1:len(self.string) - 1] + self.def_type = self.string.split()[0] + self.name = self.string.split()[1] + # get the value string inside '[' and ']' + self.value_str = self.string[self.string.index('[') + 1:self.string.index(']')].strip() + self.make_value_segments() + return True + + +if __name__ == '__main__': + local_dir = os.path.dirname(os.path.realpath(__file__)) + output_file = local_dir + '/' + sys.argv[1] + target_md_files = [] + for arg in sys.argv[2:]: + target_md_files.append(local_dir + '/' + arg) + segment_list = [] + for md_file in target_md_files: + with open(md_file) as file: + current_segment = None + for line in file.readlines(): + stripped_line = line.strip() + if stripped_line.startswith(";;"): + continue + if stripped_line.count("(") > 0 or current_segment is not None: + char_index = 0 + # add a space at the end of the stripped_line for further split + stripped_line += " " + while char_index < len(stripped_line): + if stripped_line[char_index] == '(' and current_segment is None: + # new segment start + current_segment = DefSegment() + current_segment.append('(') + elif current_segment is not None: + current_segment.append(stripped_line[char_index]) + if current_segment.is_intact(): + segment_list.append(current_segment) + current_segment = None + char_index += 1 + output_str = get_prologue() + for segment in segment_list: + if not segment.parse(): + continue + if segment.def_type == "define_mode_iterator": + output_str += gen_mode_iterator(segment) + elif segment.def_type == "define_mode_attr": + output_str += gen_mode_attr(segment) + output_str += get_epilogue() + write_to_file(output_file, output_str, opt='w') \ No newline at end of file diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 795132a0c16..9bd2f1227a8 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -36,6 +36,13 @@ along with GCC; see the file COPYING3. If not see #include "stor-layout.h" #include "expr.h" #include "langhooks.h" +#include "backend.h" +#include "gimple.h" +#include "stringpool.h" +#include "explow.h" +#include "gimple-iterator.h" +#include "riscv-protos.h" +#include "riscv-vector-builtins.h" /* Macros to create an enumeration identifier for a function prototype. */ #define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE @@ -189,6 +196,7 @@ riscv_build_function_type (enum riscv_function_type type) void riscv_init_builtins (void) { + riscv_vector::init_builtins (); for (size_t i = 0; i < ARRAY_SIZE (riscv_builtins); i++) { const struct riscv_builtin_description *d = &riscv_builtins[i]; @@ -196,7 +204,8 @@ 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; } } @@ -205,11 +214,20 @@ riscv_init_builtins (void) /* Implement TARGET_BUILTIN_DECL. */ tree -riscv_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED) +riscv_builtin_decl (unsigned int code, bool initialize_p) { - 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 @@ -271,20 +289,29 @@ riscv_expand_builtin_direct (enum insn_code icode, rtx target, tree exp, rtx riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, - int ignore ATTRIBUTE_UNUSED) + machine_mode mode ATTRIBUTE_UNUSED, + int ignore 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_VECTOR: + return riscv_vector::expand_builtin (subcode, exp, target); + case RISCV_BUILTIN_GENERAL: + { + const struct riscv_builtin_description *d = &riscv_builtins[subcode]; - case RISCV_BUILTIN_DIRECT_NO_TARGET: - return riscv_expand_builtin_direct (d->icode, target, exp, false); + 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 (); @@ -307,3 +334,36 @@ riscv_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) *clear = build_call_expr (fsflags, 1, old_flags); *update = NULL_TREE; } + +/* Implement TARGET_GIMPLE_FOLD_BUILTIN. */ + +bool +riscv_gimple_fold_builtin (gimple_stmt_iterator *gsi) +{ + + gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi)); + tree fndecl = gimple_call_fndecl (stmt); + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> RISCV_BUILTIN_SHIFT; + gimple *new_stmt = NULL; + switch (code & RISCV_BUILTIN_CLASS) + { + /* Gernal builtin can fold gimple if necessary, + may wrapp it into a function in the future. */ + case RISCV_BUILTIN_GENERAL: + return false; + + case RISCV_BUILTIN_VECTOR: + new_stmt = riscv_vector::gimple_fold_builtin (subcode, gsi, stmt); + break; + } + + if (!new_stmt) + return false; + + gsi_replace (gsi, new_stmt, true); + + return true; +} + +#include "gt-riscv-builtins.h" \ No newline at end of file diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 19c50f0e702..1cb3586d1f1 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -87,6 +87,7 @@ extern void riscv_atomic_assign_expand_fenv (tree *, tree *, tree *); extern rtx riscv_expand_builtin (tree, rtx, rtx, machine_mode, int); extern tree riscv_builtin_decl (unsigned int, bool); extern void riscv_init_builtins (void); +extern bool riscv_gimple_fold_builtin (gimple_stmt_iterator *); /* Routines implemented in riscv-common.cc. */ extern std::string riscv_arch_str (bool version_p = true); @@ -116,4 +117,22 @@ extern unsigned int rvv_offset_temporaries (bool, poly_int64); extern enum vlmul_field_enum riscv_classify_vlmul_field (machine_mode); extern int rvv_regsize (machine_mode); +/* We classify builtin types into two classes: + 1. General builtin class which is using the + original builtin architecture built in + RISCV. + 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 vector_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-functions.cc b/gcc/config/riscv/riscv-vector-builtins-functions.cc new file mode 100644 index 00000000000..19bcb66a83f --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins-functions.cc @@ -0,0 +1,1012 @@ +/* Intrinsic implementation for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zh...@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 +<http://www.gnu.org/licenses/>. */ + +#define IN_TARGET_CODE 1 + +#include "riscv-vector-builtins-functions.h" +namespace riscv_vector +{ + +extern hash_table<registered_function_hasher> *function_table; +extern GTY (()) tree + vector_types[MAX_TUPLE_NUM][NUM_VECTOR_TYPES + 1][MAX_VLMUL_FIELD]; +extern GTY (()) tree + vector_pointer_types[NUM_VECTOR_TYPES + 1][MAX_VLMUL_FIELD]; +extern GTY(()) tree scalar_types[NUM_VECTOR_TYPES]; +extern GTY(()) tree scalar_pointer_types[NUM_VECTOR_TYPES]; +extern GTY(()) tree const_scalar_pointer_types[NUM_VECTOR_TYPES]; + +extern GTY (()) vec<registered_function *, va_gc> *registered_functions; + +/* 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_RAISE_LD_EXCEPTIONS = 1U << 2; +static const unsigned int CP_READ_MEMORY = 1U << 3; +static const unsigned int CP_WRITE_MEMORY = 1U << 4; +static const unsigned int CP_READ_CSR = 1U << 5; +static const unsigned int CP_WRITE_CSR = 1U << 6; + +/* True if we've already complained about attempts to use functions + when the required extension is disabled. */ +static bool reported_missing_extension_p; + +static tree +mode2mask_t (machine_mode mode) +{ + int factor = exact_div (GET_MODE_NUNITS (mode), GET_MODE_NUNITS (VNx2BImode)) + .to_constant (); + factor = exact_log2 (factor); + return vector_types[0][VECTOR_TYPE_bool][factor]; +} + +static enum vector_type_index +get_type_idx (machine_mode mode, bool u) +{ + #define RVV_INT_TYPE(MODE, TYPE, SEW) \ + case MODE: \ + return u ? VECTOR_TYPE_u##TYPE##SEW : VECTOR_TYPE_##TYPE##SEW; \ + break; + #define RVV_FLOAT_TYPE(MODE, TYPE, SEW) \ + case MODE: \ + return VECTOR_TYPE_##TYPE##SEW; \ + break; + + switch (mode) + { + case BImode: + return VECTOR_TYPE_bool; + RVV_INT_TYPE (QImode, int, 8) + RVV_INT_TYPE (HImode, int, 16) + RVV_INT_TYPE (SImode, int, 32) + RVV_INT_TYPE (DImode, int, 64) + RVV_FLOAT_TYPE (SFmode, float, 32) + RVV_FLOAT_TYPE (DFmode, float, 64) + default: + gcc_unreachable (); + } + + return (enum vector_type_index) 0; +} + +static int +get_lmul_idx (machine_mode mode) +{ + machine_mode innermode = GET_MODE_INNER (mode); + bool is_bool_p = GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL ? true : false; + machine_mode base_mode = is_bool_p ? VNx2QImode : VNx2BImode; + int offset = exact_div (GET_MODE_NUNITS (mode), GET_MODE_NUNITS (base_mode)) + .to_constant (); + if (is_bool_p) + return exact_log2 (offset); + else + { + int nf = 1; + offset = exact_log2 (offset / nf); + int factor = exact_log2 (GET_MODE_BITSIZE (innermode).to_constant () / + GET_MODE_BITSIZE (QImode)); + return offset + factor; + } +} + +static tree +get_dt_t (machine_mode mode, bool u, bool ptr = false, bool c = false) +{ + if (mode == VOIDmode) + return void_type_node; + + machine_mode innermode = GET_MODE_INNER (mode); + enum vector_type_index base = get_type_idx (innermode, u); + tree type = NULL_TREE; + if (VECTOR_MODE_P (mode)) + { + int offset = get_lmul_idx (mode); + if (ptr) + type = vector_pointer_types[base][offset]; + else + type = vector_types[0][base][offset]; + + gcc_assert (type); + return type; + } + + if (ptr) + { + if (c) + type = const_scalar_pointer_types[base]; + else + type = scalar_pointer_types[base]; + } + else + type = scalar_types[base]; + + gcc_assert (type); + return type; +} + +/* Return true if the function has no return value. */ +static bool +function_returns_void_p (tree fndecl) +{ + return TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; +} + +/* Take argument ARGNO from EXP's argument list and convert it into + an expand operand. Store the operand in *OP. */ + +static void +add_input_operand (struct expand_operand *op, tree exp, unsigned argno) +{ + tree arg = CALL_EXPR_ARG (exp, argno); + rtx x = expand_normal (arg); + create_input_operand (op, x, TYPE_MODE (TREE_TYPE (arg))); +} + +/* Expand instruction ICODE as part of a built-in function sequence. + Use the first NOPS elements of OPS as the instruction's operands. + HAS_TARGET_P is true if operand 0 is a target; it is false if the + instruction has no target. + + Return the target rtx if HAS_TARGET_P, otherwise return const0_rtx. */ + +static rtx +generate_builtin_insn (enum insn_code icode, unsigned int n_ops, + struct expand_operand *ops, bool has_target_p) +{ + if (!maybe_expand_insn (icode, n_ops, ops)) + { + error ("invalid argument to built-in function"); + return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx; + } + + return has_target_p ? ops[0].value : const0_rtx; +} + +/* Return a hash code for a function_instance. */ +static hashval_t +get_string_hash (const char * input_string) +{ + if (!input_string || strlen (input_string) == 0) + return 0; + + inchash::hash h; + + for (unsigned int i = 0; i < strlen (input_string); i += 4) + { + unsigned int four_chars = 0; + + for (unsigned int j = i; j < strlen (input_string) && j < i + 4; j++) + { + four_chars |= input_string[j] << (8 * (j - i)); + } + + h.add_int (four_chars); + } + + return h.end (); +} + +/* Report an error against LOCATION that the user has tried to use + function FNDECL when extension EXTENSION is disabled. */ +static void +report_missing_extension (location_t location, tree fndecl, + const char *extension) +{ + /* Avoid reporting a slew of messages for a single oversight. */ + if (reported_missing_extension_p) + return; + + error_at (location, "rvv function %qD requires ISA extension %qs", fndecl, + extension); + inform (location, + "you can enable %qs using the command-line" + " option %<-march%>", + extension); + reported_missing_extension_p = true; +} + +/* Add attribute NAME to ATTRS. */ +static tree +add_attribute (const char *name, tree attrs) +{ + return tree_cons (get_identifier (name), NULL_TREE, attrs); +} + +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; +} + +/* function_instance class implemention */ + +function_instance::function_instance (function_builder *__builder, + const char *__base_name, + vector_arg_modes &__arg_pattern, + enum predication_index __pred, + enum operation_index __operation) + : m_builder (__builder), m_base_name (__base_name), + m_target_arg_pattern (__arg_pattern), m_target_pred (__pred), + m_target_operation (__operation) +{ + function_name[0] = '\0'; +} + +function_instance::function_instance (const char *__name) +{ + memcpy (function_name, __name, NAME_MAXLEN); +} + +function_instance::~function_instance () +{ +} + +inline bool +function_instance::operator== (const function_instance &other) const +{ + return (strcmp (function_name, other.function_name) == 0); +} + +inline bool +function_instance::operator!= (const function_instance &other) const +{ + return !operator== (other); +} + +/* Return a hash code for a function_instance. */ +hashval_t +function_instance::hash () const +{ + return get_string_hash (function_name); +} + +bool +function_instance::check (location_t, tree, tree, unsigned int, tree *) const +{ + return true; +} + +/* 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 = m_builder->call_properties (); + + /* -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 | CP_RAISE_LD_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 | CP_RAISE_LD_EXCEPTIONS)) + return true; + + /* Handle functions that could raise SIGBUS or SIGSEGV. */ + if (flags & (CP_READ_MEMORY | CP_WRITE_MEMORY)) + return true; + + return false; +} + +const char * +function_instance::get_base_name () const +{ + return m_base_name; +} + +vector_arg_modes +function_instance::get_arg_pattern () const +{ + return m_target_arg_pattern; +} + +enum predication_index +function_instance::get_pred () const +{ + return m_target_pred; +} + +unsigned int +function_instance::get_vma_vta () const +{ + return any_policy; +} + +enum operation_index +function_instance::get_operation () const +{ + return m_target_operation; +} + +enum data_type_index * +function_instance::get_data_type_list () const +{ + return m_builder->get_data_type_list (); +} + +function_builder * +function_instance::builder () const +{ + return m_builder; +} + +/* function_builder class implemention */ + +function_builder::function_builder (const char *__base_name, + vector_arg_all_modes &__arg_patterns, + uint64_t __pattern, + uint64_t __preds, + uint64_t __op_types, + const unsigned int __extensions) + : m_base_name (__base_name), m_target_arg_patterns (__arg_patterns), + m_target_pattern (__pattern), m_target_preds (__preds), + m_target_op_types (__op_types), m_required_extensions (__extensions) +{ + m_iter_idx_cnt = 0; + m_iter_arg_cnt = 0; + m_iter_arg_idx_list = (unsigned int *)xmalloc (m_target_arg_patterns.arg_len * + sizeof (unsigned int)); + + for (unsigned int i = 0; i < m_target_arg_patterns.arg_len; i++) + { + // use mode iterator as mode iter + if (m_target_arg_patterns.target_op_list[i] < 0) + { + m_iter_idx_cnt = + (m_iter_idx_cnt == 0) + ? m_target_arg_patterns.arg_list[i]->attr_len + : m_iter_idx_cnt * + m_target_arg_patterns.arg_list[i]->attr_len; + m_iter_arg_idx_list[m_iter_arg_cnt++] = i; + } + } + + m_direct_overloads = lang_GNU_CXX (); + + gcc_assert (m_iter_arg_cnt > 0); + gcc_assert (m_iter_idx_cnt > 0); + + gcc_obstack_init (&m_string_obstack); +} + +function_builder::~function_builder () +{ + free (m_iter_arg_idx_list); + obstack_free (&m_string_obstack, NULL); +} + +/* 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); +} + +rtx +function_builder::expand_builtin_insn (enum insn_code icode, tree exp, + rtx target, + const function_instance &instance) const +{ + gcc_assert (call_expr_nargs (exp) > 0); + struct expand_operand ops[MAX_RECOG_OPERANDS]; + machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + enum predication_index pred = instance.get_pred (); + + /* Map any target to operand 0. */ + int opno = 0; + int offset = 0; + + if (!function_returns_void_p (fndecl)) + create_output_operand (&ops[opno++], target, mode); + + if (need_mask_operand_p ()) + { + if (has_mask_arg_p (pred)) + add_input_operand (&ops[opno++], exp, offset++); + else + create_input_operand (&ops[opno++], const0_rtx, Pmode); + } + + if (need_dest_operand_p ()) + { + if (has_dest_arg_p (pred)) + add_input_operand (&ops[opno++], exp, offset++); + else + create_input_operand (&ops[opno++], const0_rtx, Pmode); + } + + for (int argno = offset; argno < call_expr_nargs (exp); argno++) + add_input_operand (&ops[opno++], exp, argno); + + if (pred != PRED_none) + create_input_operand (&ops[opno++], GEN_INT (get_policy (pred)), Pmode); + + /* Map the arguments to the other operands. */ + gcc_assert (opno == insn_data[icode].n_generator_args); + return generate_builtin_insn (icode, opno, ops, + !function_returns_void_p (fndecl)); +} + +gimple * +function_builder::fold (const function_instance &, gimple_stmt_iterator *, + gcall *) const +{ + return NULL; +} + +tree +function_builder::get_return_type (const function_instance &) const +{ + return void_type_node; +} + +size_t +function_builder::get_dest_arguments_length () const +{ + return 1; +} + +tree +function_builder::get_mask_type (tree return_type, + const function_instance &instance, + const vec<tree> &) const +{ + tree type = return_type; + if (!VECTOR_MODE_P (TYPE_MODE (type))) + { + /* Fetch the vector mode start from arg[0]. */ + for (unsigned int i = 0; i < instance.get_arg_pattern ().arg_len; i++) + { + if (VECTOR_MODE_P (instance.get_arg_pattern ().arg_list[i])) + { + type = + get_dt_t (instance.get_arg_pattern ().arg_list[i], + instance.get_data_type_list ()[i] == DT_unsigned); + break; + } + } + } + gcc_assert (VECTOR_MODE_P (TYPE_MODE (type))); + if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_BOOL) + return type; + else + { + machine_mode mask_mode; + gcc_assert ( + rvv_get_mask_mode (TYPE_MODE (type)).exists (&mask_mode)); + return mode2mask_t (mask_mode); + } +} + +void +function_builder::get_argument_types (const function_instance &, + vec<tree> &) const +{ +} + +char * +function_builder::assemble_name (function_instance &) +{ + return nullptr; +} + +uint64_t +function_builder::get_pattern () const +{ + return m_target_pattern; +} + +bool +function_builder::need_mask_operand_p () const +{ + uint64_t pat = get_pattern (); + + return (pat & PAT_mask) || (pat & PAT_merge); +} + +bool +function_builder::need_dest_operand_p () const +{ + uint64_t pat = get_pattern (); + + return (pat & PAT_tail) || ((pat & PAT_mask) && !(pat & PAT_ignore_policy)); +} + +bool +function_builder::has_mask_arg_p (enum predication_index pred) const +{ + uint64_t pat = get_pattern (); + + return pred == PRED_m || pred == PRED_tam || pred == PRED_tum || + pred == PRED_tama || pred == PRED_tamu || pred == PRED_tuma || + pred == PRED_tumu || pred == PRED_ma || pred == PRED_mu || + (pat & PAT_merge); +} + +bool +function_builder::has_dest_arg_p (enum predication_index pred) const +{ + uint64_t pat = get_pattern (); + + switch (pred) + { + case PRED_void: + return (pat & PAT_void_dest) || (pat & PAT_dest); + case PRED_ta: + case PRED_tama: + return (pat & PAT_dest); + case PRED_m: + return !(pat & PAT_ignore_policy); + case PRED_tu: + case PRED_tum: + case PRED_mu: + case PRED_tamu: + case PRED_tuma: + case PRED_tumu: + return true; + default: + return false; + } +} + +bool +function_builder::can_be_overloaded_p (const function_instance &) const +{ + return false; +} + +unsigned int +function_builder::get_policy (enum predication_index pred) const +{ + uint64_t pat = get_pattern (); + + switch (pred) + { + case PRED_void: + return (pat & PAT_void_dest || pat & PAT_dest) ? tu_policy : ta_policy; + case PRED_m: + if (pat & PAT_ignore_policy) + return any_policy; + else if (pat & PAT_ignore_mask_policy) + return tu_policy; + else if (pat & PAT_ignore_tail_policy) + return mu_policy; + else + return tumu_policy; + case PRED_ta: + case PRED_tam: + return ta_policy; + case PRED_tu: + case PRED_tum: + return tu_policy; + case PRED_ma: + return ma_policy; + case PRED_mu: + return mu_policy; + case PRED_tama: + return tama_policy; + case PRED_tamu: + return tamu_policy; + case PRED_tuma: + return tuma_policy; + case PRED_tumu: + return tumu_policy; + default: + return any_policy; + } +} + +size_t +function_builder::get_position_of_mask_arg (enum predication_index) const +{ + return 0; +} + +size_t +function_builder::get_position_of_dest_arg (enum predication_index pred) const +{ + uint64_t pat = get_pattern (); + if (pred == PRED_tu || + (pred == PRED_void && (pat & PAT_void_dest || pat & PAT_dest)) || + (pred == PRED_ta && pat & PAT_dest)) + return 0; + else + return 1; +} + +unsigned int +function_builder::call_properties () const +{ + return 0; +} + +enum data_type_index * +function_builder::get_data_type_list () const +{ + return m_target_arg_patterns.dt_list; +} + +/* Return the appropriate function attributes for INSTANCE. */ +tree +function_builder::get_attributes (const function_instance &instance) const +{ + 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 and OVERLOADED_P indicates + whether it is overloaded. REQUIRED_EXTENSIONS are the set of + architecture extensions that the function requires. */ +registered_function & +function_builder::add_function (const function_instance &instance, + const char *name, tree fntype, tree attrs, + bool overloaded_p, + bool placeholder_p) const +{ + 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<registered_function> (); + rfn.instance = instance; + rfn.decl = decl; + rfn.overloaded_p = overloaded_p; + rfn.required_extensions = m_required_extensions; + 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. + REQUIRED_EXTENSIONS are the set of architecture extensions that the + function requires. FORCE_DIRECT_OVERLOADS is true if there is a + one-to-one mapping between "short" and "full" names, and if standard + overload resolution therefore isn't necessary. */ +void +function_builder::add_unique_function (function_instance &instance, + tree return_type, + vec<tree> &argument_types) +{ + /* Add the function under its full (unique) name. */ + char *overloaded_name = this->assemble_name (instance); + if (instance.function_name[0] == '\0') + return; + + 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, instance.function_name, fntype, attrs, false, false); + + /* Enter the function into the hash table. */ + hashval_t hashval = instance.hash (); + registered_function **rfn_slot = + function_table->find_slot_with_hash (instance, hashval, INSERT); + + if (*rfn_slot) + { + error ("duplicate function name: %s", instance.function_name); + gcc_unreachable (); + } + + *rfn_slot = &rfn; + + if (overloaded_name) + { + /* Attribute lists shouldn't be shared. */ + tree attrs = get_attributes (instance); + bool placeholder_p = !m_direct_overloads; + add_function (instance, overloaded_name, fntype, attrs, + false, placeholder_p); + obstack_free (&m_string_obstack, overloaded_name); + } +} + +/* Check whether all the RISCV_* values in REQUIRED_EXTENSIONS are + enabled, given that those extensions are required for function FNDECL. + Report an error against LOCATION if not. */ +bool +function_builder::check_required_extensions (location_t location, tree fndecl, + uint64_t required_extensions) const +{ + /* For the instructions doesn't need any extension, we return true. */ + if (required_extensions == 0) + return true; + + /* check vector extension enable or not. */ + if ((required_extensions & 0x1) && !TARGET_VECTOR) + report_missing_extension (location, fndecl, "V"); + + /* check f extension enable or not. */ + if (((required_extensions >> 4) & 0x1) && !TARGET_HARD_FLOAT) + report_missing_extension (location, fndecl, "F"); + + /* check d extension enable or not. */ + if (((required_extensions >> 5) & 0x1) && !TARGET_DOUBLE_FLOAT) + report_missing_extension (location, fndecl, "D"); + + return true; +} + +/* If INSTANCE has a governing predicate, add it to the list of argument + types in ARGUMENT_TYPES. RETURN_TYPE is the type returned by the + function. */ +void +function_builder::apply_predication (const function_instance &instance, + tree return_type, + vec<tree> &argument_types) const +{ + /* check if mask parameter need. */ + if (has_mask_arg_p (instance.get_pred ())) + { + argument_types.quick_insert ( + get_position_of_mask_arg (instance.get_pred ()), + get_mask_type (return_type, instance, argument_types)); + } + + /* check if dest parameter need. */ + if (has_dest_arg_p (instance.get_pred ())) + { + size_t size = get_dest_arguments_length (); + if (argument_types.is_empty ()) + for (size_t i = 0; i < size; i += 1) + argument_types.quick_push (return_type); + else + for (size_t i = 0; i < size; i += 1) + argument_types.quick_insert (get_position_of_dest_arg (instance.get_pred ()) + i, + return_type); + } + + /* check if vl parameter need */ + if (instance.get_pred () != PRED_none) + argument_types.quick_push (size_type_node); +} + +void +function_builder::build_one (function_instance &instance) +{ + /* Byte forms of vlxusegei take 21 arguments. */ + auto_vec<tree, 21> argument_types; + tree return_type = get_return_type (instance); + get_argument_types (instance, argument_types); + apply_predication (instance, return_type, argument_types); + add_unique_function (instance, return_type, argument_types); +} + +vector_arg_modes & +function_builder::get_arg_modes_by_iter_idx (unsigned int iter_idx) const +{ + if (iter_idx >= m_iter_idx_cnt) + { + gcc_unreachable (); + } + + unsigned int coefficient = 1; + machine_mode *arg_modes = (machine_mode *)xmalloc ( + sizeof (machine_mode) * m_target_arg_patterns.arg_len); + vector_arg_modes &arg_modes_info = + *(vector_arg_modes *)xmalloc (sizeof (vector_arg_modes)); + arg_modes_info.arg_len = m_target_arg_patterns.arg_len; + arg_modes_info.arg_list = arg_modes; + arg_modes_info.arg_extensions = m_required_extensions; + + // set mode for iter args first + for (unsigned int i = 0; i < m_iter_arg_cnt; i++) + { + // get the iter arg's attribute length + unsigned int arg_attr_len = + m_target_arg_patterns.arg_list[m_iter_arg_idx_list[i]]->attr_len; + vector_mode_attr target_mode_attr = + m_target_arg_patterns.arg_list[m_iter_arg_idx_list[i]] + ->attr_list[(iter_idx / coefficient) % arg_attr_len]; + arg_modes[m_iter_arg_idx_list[i]] = target_mode_attr.mode; + arg_modes_info.arg_extensions |= target_mode_attr.extension; + coefficient *= arg_attr_len; + } + + // set mode for attr args + for (unsigned int i = 0; i < m_target_arg_patterns.arg_len; i++) + { + // skip iter args + if (m_target_arg_patterns.target_op_list[i] < 0) + continue; + + machine_mode iter_mode = + arg_modes[m_target_arg_patterns.target_op_list[i]]; + vector_mode_attr_list *arg_attr_list = m_target_arg_patterns.arg_list[i]; + bool attr_mode_hit = false; + + for (unsigned int j = 0; j < arg_attr_list->attr_len; j++) + { + if (iter_mode == arg_attr_list->attr_list[j].mode) + { + attr_mode_hit = true; + arg_modes[i] = arg_attr_list->attr_list[j].attr; + arg_modes_info.arg_extensions |= + arg_attr_list->attr_list[j].extension; + } + } + + // one argment mode NOT hit, that means maybe NO mode is valid for + // iter_idx + if (!attr_mode_hit) + { + // set arg_len to 0 to skip this arg pattern + arg_modes_info.arg_len = 0; + break; + } + } + + return arg_modes_info; +} + +void +function_builder::register_function () +{ + for (unsigned iter_idx = 0; iter_idx < m_iter_idx_cnt; iter_idx++) + { + vector_arg_modes &arg_modes = get_arg_modes_by_iter_idx (iter_idx); + + bool skip_p = false; + if (arg_modes.arg_len == 0) + skip_p = true; + + if (FLOAT_MODE_P (arg_modes.arg_list[0]) && + get_data_type_list ()[0] == DT_unsigned) + skip_p = true; + + if (skip_p) + { + free (arg_modes.arg_list); + free (&arg_modes); + continue; + } + for (unsigned pred = 1; pred < NUM_PREDS; pred <<= 1) + { + if ((m_target_preds & pred) == 0) + continue; + + for (unsigned op_type = 1; op_type < NUM_OP; op_type <<= 1) + { + if ((m_target_op_types & op_type) == 0) + continue; + + function_instance instance ( + this, m_base_name, arg_modes, + (enum predication_index) (m_target_preds & pred), + (enum operation_index) (m_target_op_types & op_type)); + build_one (instance); + } + } + } +} + +} // end namespace riscv_vector + +using 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-functions.h" \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector-builtins-functions.def b/gcc/config/riscv/riscv-vector-builtins-functions.def new file mode 100644 index 00000000000..f6161012813 --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins-functions.def @@ -0,0 +1,34 @@ +/* Intrinsic macros for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zh...@rivai.ai), RiVAI Technologies Ltd. + Based on MIPS target for GNU compiler. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef DEF_RVV_FUNCTION +#define DEF_RVV_FUNCTION(A, B, C, D, E, F, G) +#endif +#ifndef VITER +#define VITER(A) +#endif +#ifndef VATTR +#define VATTR(A, B) +#endif + +#undef DEF_RVV_FUNCTION +#undef VITER +#undef VATTR \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector-builtins-functions.h b/gcc/config/riscv/riscv-vector-builtins-functions.h new file mode 100644 index 00000000000..1b769743857 --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins-functions.h @@ -0,0 +1,491 @@ +/* Intrinsic definitions for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zh...@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 + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_RISCV_VECTOR_BUILTINS_FUNCTIONS_H +#define GCC_RISCV_VECTOR_BUILTINS_FUNCTIONS_H + +#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 "recog.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "expr.h" +#include "basic-block.h" +#include "function.h" +#include "fold-const.h" +#include "varasm.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimplify.h" +#include "explow.h" +#include "emit-rtl.h" +#include "tree-vector-builder.h" +#include "stor-layout.h" +#include "regs.h" +#include "alias.h" +#include "gimple-fold.h" +#include "langhooks.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-pass.h" +#include "tree-vrp.h" +#include "tree-ssanames.h" +#include "tree-ssa-operands.h" +#include "tree-phinodes.h" +#include "targhooks.h" +#include "langhooks-def.h" +#include "riscv-vector.h" +#include <string> + +namespace riscv_vector +{ + +/* The macro defines the maximum length of name string. */ +static const unsigned int NAME_MAXLEN = 32; +/* The macro defines the maxmum number of tuple. For + RISC-V 'V' Extension, the maxmum tuple number is 8. + TODO: We will support tuple type for segment instructions later. */ +static const unsigned int MAX_TUPLE_NUM = 1; + +/* Describes the various of data_type. + Used by riscv-vector-builtins-iterators.def. */ +enum data_type_index +{ + /* signed data. */ + DT_signed, + /* unsigned data. */ + DT_unsigned, + /* signed data pointer. */ + DT_ptr, + /* unsigned data pointer. */ + DT_uptr, + /* const signed data pointer. */ + DT_c_ptr, + /* const unsigned data pointer. */ + DT_c_uptr, +}; + +/* Describes the various uses of a governing predicate. + Used by riscv-vector-builtins-iterators.def. */ +enum predication_index +{ + /* No governing predicate is present. */ + PRED_none = 1 << 0, + /* tail agnostic, ignore mask policy */ + PRED_ta = 1 << 3, + /* tail undisturbed, ignore mask policy */ + PRED_tu = 1 << 4, + /* mask agnostic, ignore tail policy */ + PRED_ma = 1 << 5, + /* mask undisturbed, ignore tail policy */ + PRED_mu = 1 << 6, + /* mask and tail both agnostic */ + PRED_tama = 1 << 7, + /* mask undisturbed and tail agnostic */ + PRED_tamu = 1 << 8, + /* mask agnostic and tail undisturbed */ + PRED_tuma = 1 << 9, + /* mask and tail both undisturbed */ + PRED_tumu = 1 << 10, + /* No governing predicate is present. */ + PRED_void = 1 << 11, + /* mask and tail both undisturbed */ + PRED_m = 1 << 12, + /* tail agnostic, ignore mask policy */ + PRED_tam = 1 << 13, + /* tail undisturbed, ignore mask policy */ + PRED_tum = 1 << 14, + + NUM_PREDS +}; + +/* Describes the various intrinsic types. */ +enum intrinsic_pattern +{ + /* other intrinsic */ + PAT_none = 1 << 0, + PAT_mask = 1 << 1, + PAT_tail = 1 << 2, + PAT_dest = 1 << 3, + PAT_void_dest = 1 << 4, + PAT_ignore_mask_policy = 1 << 5, + PAT_ignore_tail_policy = 1 << 6, + PAT_ignore_policy = 1 << 7, + PAT_merge = 1 << 8, +}; + +/* Describes the various operation types. */ +enum operation_index +{ + OP_none = 1 << 0, + OP_vv = 1 << 1, + OP_vx = 1 << 2, + OP_v = 1 << 3, + OP_wv = 1 << 4, + OP_wx = 1 << 5, + OP_x_x_v = 1 << 6, + OP_vf2 = 1 << 7, + OP_vf4 = 1 << 8, + OP_vf8 = 1 << 9, + OP_vvm = 1 << 10, + OP_vxm = 1 << 11, + OP_x_x_w = 1 << 12, + OP_v_v = 1 << 13, + OP_v_x = 1 << 14, + OP_vs = 1 << 15, + OP_mm = 1 << 16, + OP_m = 1 << 17, + OP_vf = 1 << 18, + OP_vm = 1 << 19, + OP_wf = 1 << 20, + OP_vfm = 1 << 21, + OP_v_f = 1 << 22, + NUM_OP +}; + +/* Describe indexed-ordered or indexed-unordered load store. */ +enum indexed_mode +{ + INDEXED_u, + INDEXED_o, +}; + +/* Describe vector policy. */ +enum vector_policy +{ + undisturbed = 0, + agnostic = 1, + any = 2, +}; + +/* Enumerates the VECTOR (data) vector types, together called + "vector types" for brevity. */ +enum vector_type_index +{ +#define DEF_RVV_TYPE(ELEM_TYPE, NODE) VECTOR_TYPE_##ELEM_TYPE, +#include "riscv-vector-builtins.def" + NUM_VECTOR_TYPES +#undef DEF_RVV_TYPE +}; + +struct vector_vlmul_info +{ + enum vlmul_field_enum vlmul; + const char *suffix; + const char *boolnum; +}; + +struct vector_type_info +{ + enum vector_type_index type; + const char *elem_name; +}; + +// for function arg mode infomation, include return type +struct vector_mode_attr +{ + machine_mode mode; + machine_mode attr; + // the extension like TARGET_VECTOR + uint64_t extension; +}; + +// the total variable pack for function arg mode infomation, include return +// type +struct vector_mode_attr_list +{ + unsigned int attr_len; + vector_mode_attr *attr_list; +}; + +// for VATTR(OP, MODE_ATTR) +struct vector_arg_attr_info +{ + int target_op; + enum data_type_index dt; + vector_mode_attr_list *mode_attr_list; +}; + +struct vector_arg_all_modes +{ + unsigned int arg_len; + data_type_index *dt_list; + int *target_op_list; + // arg_list[0] is always return type + vector_mode_attr_list **arg_list; +}; + +struct vector_arg_modes +{ + uint64_t arg_extensions; + unsigned int arg_len; + // arg_list[0] is always return type + machine_mode *arg_list; +}; + +constexpr unsigned int +get_vma_vta (vector_policy vma, vector_policy vta) +{ + return (vma << 2) | vta; +} + +constexpr vector_policy +get_vma (unsigned int vma_vta) +{ + return (vector_policy)((vma_vta >> 2) & 0b11); +} + +constexpr vector_policy +get_vta (unsigned int vma_vta) +{ + return (vector_policy)(vma_vta & 0b11); +} + +const unsigned int tama_policy = get_vma_vta(vector_policy::agnostic, vector_policy::agnostic); +const unsigned int tamu_policy = get_vma_vta(vector_policy::undisturbed, vector_policy::agnostic); +const unsigned int tuma_policy = get_vma_vta(vector_policy::agnostic, vector_policy::undisturbed); +const unsigned int tumu_policy = get_vma_vta(vector_policy::undisturbed, vector_policy::undisturbed); +const unsigned int ta_policy = get_vma_vta(vector_policy::any, vector_policy::agnostic); +const unsigned int tu_policy = get_vma_vta(vector_policy::any, vector_policy::undisturbed); +const unsigned int ma_policy = get_vma_vta(vector_policy::agnostic, vector_policy::any); +const unsigned int mu_policy = get_vma_vta(vector_policy::undisturbed, vector_policy::any); +const unsigned int any_policy = get_vma_vta(vector_policy::any, vector_policy::any); + +inline rtx +gen_tama_policy () +{ + return gen_rtx_CONST_INT (Pmode, tama_policy); +} + +inline rtx +gen_tamu_policy () +{ + return gen_rtx_CONST_INT (Pmode, tamu_policy); +} + +inline rtx +gen_tuma_policy () +{ + return gen_rtx_CONST_INT (Pmode, tuma_policy); +} + +inline rtx +gen_tumu_policy () +{ + return gen_rtx_CONST_INT (Pmode, tumu_policy); +} + +inline rtx +gen_ta_policy () +{ + return gen_rtx_CONST_INT (Pmode, ta_policy); +} + +inline rtx +gen_tu_policy () +{ + return gen_rtx_CONST_INT (Pmode, tu_policy); +} + +inline rtx +gen_ma_policy () +{ + return gen_rtx_CONST_INT (Pmode, ma_policy); +} + +inline rtx +gen_mu_policy () +{ + return gen_rtx_CONST_INT (Pmode, mu_policy); +} + +inline rtx +gen_any_policy () +{ + return gen_rtx_CONST_INT (Pmode, any_policy); +} + +class function_builder; + +class GTY ((user)) function_instance +{ +public: + function_instance (function_builder *, const char *, vector_arg_modes &, + enum predication_index, enum operation_index); + function_instance (const char *__name); + ~function_instance (); + + bool operator== (const function_instance &) const; + bool operator!= (const function_instance &) const; + + hashval_t hash () const; + bool check (location_t, tree, tree, unsigned int, tree *) const; + unsigned int call_properties () const; + bool reads_global_state_p () const; + bool modifies_global_state_p () const; + bool could_trap_p () const; + + const char *get_base_name () const; + vector_arg_modes get_arg_pattern () const; + enum predication_index get_pred () const; + unsigned int get_vma_vta () const; + enum operation_index get_operation () const; + enum data_type_index *get_data_type_list () const; + function_builder *builder () const; + + char function_name[NAME_MAXLEN]; + +private: + function_builder *m_builder; + const char *m_base_name; + vector_arg_modes m_target_arg_pattern; + enum predication_index m_target_pred; + enum operation_index m_target_operation; +}; + +/* Describes a function decl. */ +class GTY (()) registered_function +{ +public: + function_instance GTY ((skip)) instance; + + /* The decl itself. */ + tree GTY ((skip)) decl; + + /* The architecture extensions that the function requires, as a set of + RISCV_TARGET_* flags. */ + uint64_t required_extensions; + + /* True if the decl represents an overloaded function that needs to be + resolved. */ + bool overloaded_p; +}; + +/* A class for building and registering function decls. */ +class function_builder +{ +public: + function_builder (const char *, vector_arg_all_modes &, uint64_t, + uint64_t, uint64_t, const unsigned int); + + virtual ~function_builder (); + + void register_function (); + + /* Try to fold the given gimple call. Return the new gimple statement + on success, otherwise return null. */ + virtual gimple * fold (const function_instance &, gimple_stmt_iterator *, gcall *) 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 (const function_instance &, tree, rtx) const = 0; + + rtx + expand_builtin_insn (enum insn_code, tree, rtx, + const function_instance &) const; + + virtual tree get_return_type (const function_instance &) const; + + virtual tree get_mask_type (tree, const function_instance &, const vec<tree> &) const; + + virtual void get_argument_types (const function_instance &, + vec<tree> &) const; + + virtual size_t get_dest_arguments_length () const; + + uint64_t get_pattern () const; + /* check if need add mask operand for corresponding rtl */ + bool need_mask_operand_p () const; + /* check if need add dest operand for corresponding rtl */ + bool need_dest_operand_p () const; + /* check if has mask arg for corresponding function decl */ + bool has_mask_arg_p (enum predication_index) const; + /* check if has dest arg for corresponding function decl */ + virtual bool has_dest_arg_p (enum predication_index) const; + unsigned int get_policy (enum predication_index) const; + /* get parameter position of mask arg */ + virtual size_t get_position_of_mask_arg (enum predication_index) const; + /* get parameter position of dest arg */ + virtual size_t get_position_of_dest_arg (enum predication_index) const; + + void apply_predication (const function_instance &, tree, vec<tree> &) const; + + virtual unsigned int call_properties () const; + + vector_arg_modes &get_arg_modes_by_iter_idx (unsigned int) const; + + enum data_type_index *get_data_type_list () const; + + bool check_required_extensions (location_t, tree, uint64_t) const; + virtual char * assemble_name (function_instance &); + void append_name (const char *); + char *finish_name (); + + /* Return true if the function can be overloaded. */ + virtual bool can_be_overloaded_p (const function_instance &) const; + +private: + void add_unique_function (function_instance &, tree, vec<tree> &); + void build_one (function_instance &); + tree get_attributes (const function_instance &) const; + + registered_function &add_function (const function_instance &, const char *, + tree, tree, bool, bool) const; + + /* The base name, as a string. */ + const char *m_base_name; + vector_arg_all_modes m_target_arg_patterns; + uint64_t m_target_pattern; + uint64_t m_target_preds; + uint64_t m_target_op_types; + uint64_t m_required_extensions; + + unsigned int m_iter_idx_cnt; + unsigned int m_iter_arg_cnt; + unsigned int *m_iter_arg_idx_list; + + /* 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; +}; + +/* Hash traits for registered_function. */ +struct registered_function_hasher : nofree_ptr_hash<registered_function> +{ + typedef function_instance compare_type; + + static hashval_t hash (value_type); + static bool equal (value_type, const compare_type &); +}; + +} // namespace riscv_vector + +#endif // end GCC_RISCV_VECTOR_BUILTINS_FUNCTIONS_H \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector-builtins-iterators.def b/gcc/config/riscv/riscv-vector-builtins-iterators.def new file mode 100644 index 00000000000..ac0c37e12d4 --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins-iterators.def @@ -0,0 +1,12 @@ +/* Do not modify this file, it auto gen by md-parser script */ +#ifndef DEF_RISCV_ARG_MODE_ATTR_VARIABLE +#define DEF_RISCV_ARG_MODE_ATTR_VARIABLE(A, B) +#endif + +#ifndef DEF_RISCV_ARG_MODE_ATTR +#define DEF_RISCV_ARG_MODE_ATTR(A, B, C, D, E) +#endif + + +#undef DEF_RISCV_ARG_MODE_ATTR_VARIABLE +#undef DEF_RISCV_ARG_MODE_ATTR diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc new file mode 100644 index 00000000000..7ea07a24b5b --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -0,0 +1,266 @@ +/* Builtins implementation for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zh...@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 + <http://www.gnu.org/licenses/>. */ + +#define IN_TARGET_CODE 1 + +#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 "recog.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "expr.h" +#include "basic-block.h" +#include "function.h" +#include "fold-const.h" +#include "varasm.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimplify.h" +#include "explow.h" +#include "emit-rtl.h" +#include "tree-vector-builder.h" +#include "stor-layout.h" +#include "regs.h" +#include "alias.h" +#include "gimple-fold.h" +#include "langhooks.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-pass.h" +#include "tree-vrp.h" +#include "tree-ssanames.h" +#include "tree-ssa-operands.h" +#include "tree-phinodes.h" +#include "targhooks.h" +#include "langhooks-def.h" +#include "riscv-vector-builtins.h" +#include "riscv-vector-builtins-functions.h" +#include "riscv-vector.h" +namespace riscv_vector +{ + +/* The same vlmul doesn't mean use the same mask, + this is used as save codes. + for example: i32m8 use vbool4_t i8m8 use vbool1_t. */ +static CONSTEXPR const vector_vlmul_info vector_vlmuls[] = +{ + { VLMUL_FIELD_101, "mf8", "64" }, { VLMUL_FIELD_110, "mf4", "32" }, + { VLMUL_FIELD_111, "mf2", "16" }, { VLMUL_FIELD_000, "m1", "8" }, + { VLMUL_FIELD_001, "m2", "4" }, { VLMUL_FIELD_010, "m4", "2" }, + { VLMUL_FIELD_011, "m8", "1" }, +}; + +static CONSTEXPR const vector_type_info vector_type_infos[] = +{ +#define DEF_RVV_TYPE(ELEM_TYPE, NODE) { VECTOR_TYPE_##ELEM_TYPE, #ELEM_TYPE }, +#include "riscv-vector-builtins.def" +#undef DEF_RVV_TYPE +}; + +static GTY(()) tree internal_vector_types[NUM_VECTOR_TYPES + 1][MAX_VLMUL_FIELD]; + +/* Same, but with the riscv_vector.h "v..._t" name. */ +GTY(()) tree vector_types[MAX_TUPLE_NUM][NUM_VECTOR_TYPES + 1][MAX_VLMUL_FIELD]; +/* Same, but with the riscv_vector.h "v..._t *" name. */ +GTY(()) tree vector_pointer_types[NUM_VECTOR_TYPES + 1][MAX_VLMUL_FIELD]; +/* The scalar type associated with each vector type. */ +GTY(()) tree scalar_types[NUM_VECTOR_TYPES]; +/* The scalar pointer type associated with each vector type. */ +GTY(()) tree scalar_pointer_types[NUM_VECTOR_TYPES]; +/* The const scalar pointer type associated with each vector type. */ +GTY(()) tree const_scalar_pointer_types[NUM_VECTOR_TYPES]; + +/* All registered function decls, hashed on the function_instance + that they implement. This is used for looking up implementations of + overloaded functions. */ +hash_table<registered_function_hasher> *function_table; + +static riscv_vector::function_builder** all_vector_functions; + +/* The list of all registered function decls, indexed by code. */ +vec<registered_function *, va_gc> *registered_functions; + +static unsigned int NUM_INSN_FUNC; + +static void init_def_variables (); + +/* Initialize all compiler built-ins related to RVV that should be + defined at start-up. */ +void +init_builtins () +{ + if (!TARGET_VECTOR) + return; +} + +/* 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; +} + +/* Perform any semantic checks needed for a call to the RVV function + with subcode CODE, such as testing for integer constant expressions. + The call occurs at location LOCATION and has NARGS arguments, + given by ARGS. FNDECL is the original function decl, before + overload resolution. + + Return true if the call is valid, otherwise report a suitable error. */ +bool +check_builtin_call (location_t location, vec<location_t>, unsigned int code, + tree fndecl, unsigned int nargs, tree *args) +{ + const registered_function &rfn = *(*registered_functions)[code]; + function_builder *builder = rfn.instance.builder (); + + if (!builder->check_required_extensions ( + location, rfn.decl, rfn.instance.get_arg_pattern ().arg_extensions)) + return false; + + return rfn.instance.check (location, fndecl, TREE_TYPE (rfn.decl), nargs, + args); +} + +/* Attempt to fold STMT, given that it's a call to the RVV function + with subcode CODE. Return the new statement on success and null + on failure. Insert any other new statements at GSI. */ +gimple * +gimple_fold_builtin (unsigned int code, gimple_stmt_iterator *gsi, gcall *stmt) +{ + registered_function &rfn = *(*registered_functions)[code]; + function_builder *builder = rfn.instance.builder (); + return builder->fold (rfn.instance, gsi, stmt); +} + +/* 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]; + function_builder *builder = rfn.instance.builder (); + + if (!builder->check_required_extensions ( + EXPR_LOCATION (exp), rfn.decl, + rfn.instance.get_arg_pattern ().arg_extensions)) + return target; + + return builder->expand (rfn.instance, exp, target); +} + +riscv_vector::vector_arg_all_modes & +get_vector_arg_all_patterns (unsigned int len, + riscv_vector::vector_arg_attr_info attr, ...) +{ + riscv_vector::vector_arg_all_modes &patterns = + *ggc_alloc<riscv_vector::vector_arg_all_modes> (); + patterns.arg_len = len; + patterns.arg_list = (riscv_vector::vector_mode_attr_list **)xmalloc ( + len * sizeof (riscv_vector::vector_mode_attr_list *)); + patterns.target_op_list = (int *)xmalloc (len * sizeof (int)); + patterns.dt_list = + (enum data_type_index *)xmalloc (len * sizeof (enum data_type_index)); + + unsigned int arg_idx = 0; + va_list arg_ptr; + riscv_vector::vector_arg_attr_info next_attr = attr; + + va_start (arg_ptr, attr); + + while (arg_idx < len) + { + patterns.dt_list[arg_idx] = next_attr.dt; + patterns.arg_list[arg_idx] = next_attr.mode_attr_list; + patterns.target_op_list[arg_idx] = next_attr.target_op; + next_attr = va_arg (arg_ptr, riscv_vector::vector_arg_attr_info); + arg_idx++; + } + + va_end (arg_ptr); + + return patterns; +} + +static vector_mode_attr_list vector_mode_attr_list_list[vector_arg_mode_category_num]; + +static void +init_def_variables () +{ + +/* define vector arg mode category */ +#define VVAR(NAME) vector_mode_attr_list_list[vector_mode_attr_##NAME] +#define VITER(NAME, SIGN) riscv_vector::vector_arg_attr_info{-1, DT_##SIGN, &VVAR(NAME)} +#define VATTR(OP, NAME, SIGN) riscv_vector::vector_arg_attr_info{OP, DT_##SIGN, &VVAR(NAME)} +#define DEF_RISCV_ARG_MODE_ATTR_VARIABLE(VARIABLE_NAME, ELEM_CNT) \ + VVAR(VARIABLE_NAME) = {ELEM_CNT, \ + (riscv_vector::vector_mode_attr*)xmalloc(ELEM_CNT * sizeof(vector_mode_attr))}; +#include "riscv-vector-builtins-iterators.def" +#undef DEF_RISCV_ARG_MODE_ATTR_VARIABLE + +/* define every vector arg mode in category */ +#define DEF_RISCV_ARG_MODE_ATTR(VARIABLE_NAME, INDEX, MODE, ATTR_MODE, \ + CONDITION) \ + VVAR (VARIABLE_NAME).attr_list[INDEX] \ + = { MODE##mode, ATTR_MODE##mode, RISCV_##CONDITION }; +#include "riscv-vector-builtins-iterators.def" +#undef DEF_RISCV_ARG_MODE_ATTR + + /* count the number of intrinsic functions */ + NUM_INSN_FUNC = 0; +#define DEF_RVV_FUNCTION(BASE_NAME, CLASS_NAME, ARG_PATTERN, INTRNSIC_PATTER, PREDS, OP_TYPES) \ + NUM_INSN_FUNC++; +#include "riscv-vector-builtins-functions.def" +#undef DEF_RVV_FUNCTION + + all_vector_functions = (riscv_vector::function_builder **)xmalloc ( + sizeof (riscv_vector::function_builder *) * NUM_INSN_FUNC); + + unsigned int func_idx = 0; +#define VITER(NAME, SIGN) \ + riscv_vector::vector_arg_attr_info { -1, DT_##SIGN, &VVAR (NAME) } +#define VATTR(OP, NAME, SIGN) \ + riscv_vector::vector_arg_attr_info { OP, DT_##SIGN, &VVAR (NAME) } +#define DEF_RVV_FUNCTION(BASE_NAME, CLASS_NAME, ARG_PATTERN, INTRNSIC_PATTER, PREDS, OP_TYPES) \ + all_vector_functions[func_idx++] = new riscv_vector::CLASS_NAME ( \ + #BASE_NAME, get_vector_arg_all_patterns ARG_PATTERN, INTRNSIC_PATTER, PREDS, OP_TYPES, \ + (REQUIRED_EXTENSIONS)); +#include "riscv-vector-builtins-functions.def" +#undef DEF_RVV_FUNCTION +} + +} //end namespace riscv_vector + +using namespace riscv_vector; + +#include "gt-riscv-vector-builtins.h" \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector-builtins.def b/gcc/config/riscv/riscv-vector-builtins.def new file mode 100644 index 00000000000..805f9d725dc --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins.def @@ -0,0 +1,37 @@ +/* Builtins macros for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zh...@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 +<http://www.gnu.org/licenses/>. */ + +#ifndef DEF_RVV_TYPE +#define DEF_RVV_TYPE(A, B) +#endif + +DEF_RVV_TYPE (bool, boolean) +DEF_RVV_TYPE (float32, float) +DEF_RVV_TYPE (float64, double) +DEF_RVV_TYPE (int8, int8) +DEF_RVV_TYPE (int16, int16) +DEF_RVV_TYPE (int32, int32) +DEF_RVV_TYPE (int64, int64) +DEF_RVV_TYPE (uint8, unsigned_int8) +DEF_RVV_TYPE (uint16, unsigned_int16) +DEF_RVV_TYPE (uint32, unsigned_int32) +DEF_RVV_TYPE (uint64, unsigned_int64) + +#undef DEF_RVV_TYPE \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h new file mode 100644 index 00000000000..6bba4c90c3a --- /dev/null +++ b/gcc/config/riscv/riscv-vector-builtins.h @@ -0,0 +1,59 @@ +/* Builtins definitions for RISC-V 'V' Extension for GNU compiler. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + Contributed by Juzhe Zhong (juzhe.zh...@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 + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_RISCV_VECTOR_BUILTINS_H +#define GCC_RISCV_VECTOR_BUILTINS_H + +#include <vector> +#include "riscv-vector-builtins-functions.h" + +namespace riscv_vector +{ + +/* global share variables */ + +static const unsigned int RISCV_TARGET_ANY = 0; +static const unsigned int RISCV_TARGET_VECTOR = 1; +static const unsigned int RISCV_TARGET_HARD_FLOAT = 1 << 2; +static const unsigned int RISCV_TARGET_DOUBLE_FLOAT = 1 << 3; + +enum vector_arg_mode_category { +#define VVAR(NAME) vector_mode_attr_##NAME +#define DEF_RISCV_ARG_MODE_ATTR_VARIABLE(VARIABLE_NAME, ELEM_CNT) \ + VVAR(VARIABLE_NAME), +#include "riscv-vector-builtins-iterators.def" +#undef DEF_RISCV_ARG_MODE_ATTR_VARIABLE +#undef VVAR + /* the number of arg mode category */ + vector_arg_mode_category_num +}; + +void init_builtins (); +void handle_pragma_vector (); +tree builtin_decl (unsigned, bool); +gimple *gimple_fold_builtin (unsigned int, gimple_stmt_iterator *, gcall *); +rtx expand_builtin (unsigned int, tree, rtx); +bool check_builtin_call (location_t, vec<location_t>, unsigned int, + tree, unsigned int, tree *); +machine_mode vector_builtin_mode (scalar_mode, enum vlmul_field_enum); + +} // end namespace riscv_vector + +#endif \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector.cc b/gcc/config/riscv/riscv-vector.cc index e315b5d2cac..87dc6739f4f 100644 --- a/gcc/config/riscv/riscv-vector.cc +++ b/gcc/config/riscv/riscv-vector.cc @@ -226,4 +226,21 @@ rvv_regsize (machine_mode mode) } return 1; +} + +/* Get related mask mode for a RVV vector mode. */ + +opt_machine_mode +rvv_get_mask_mode (machine_mode mode) +{ + machine_mode mask_mode; + int nf = 1; + + FOR_EACH_MODE_IN_CLASS (mask_mode, MODE_VECTOR_BOOL) + if (GET_MODE_INNER (mask_mode) == BImode + && known_eq (GET_MODE_NUNITS (mask_mode) * nf, + GET_MODE_NUNITS (mode)) + && rvv_mask_mode_p (mask_mode)) + return mask_mode; + return default_get_mask_mode (mode); } \ No newline at end of file diff --git a/gcc/config/riscv/riscv-vector.h b/gcc/config/riscv/riscv-vector.h index b8d77ddb195..62df507e7df 100644 --- a/gcc/config/riscv/riscv-vector.h +++ b/gcc/config/riscv/riscv-vector.h @@ -25,4 +25,5 @@ bool rvv_legitimate_poly_int_p (rtx); unsigned int rvv_offset_temporaries (bool, poly_int64); vlmul_field_enum rvv_classify_vlmul_field (machine_mode); int rvv_regsize (machine_mode); +opt_machine_mode rvv_get_mask_mode (machine_mode); #endif // GCC_RISCV_VECTOR_H \ No newline at end of file diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 37d8f1271d4..b82a38da7c9 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -4967,7 +4967,16 @@ riscv_class_max_nregs (reg_class_t rclass, machine_mode mode) if (reg_class_subset_p (rclass, GR_REGS)) return riscv_hard_regno_nregs (GP_REG_FIRST, mode); + + if (reg_class_subset_p (V_REGS, rclass)) + return riscv_hard_regno_nregs (V_REG_FIRST, mode); + + if (reg_class_subset_p (VL_REGS, rclass)) + return 1; + if (reg_class_subset_p (VTYPE_REGS, rclass)) + return 1; + return 0; } @@ -5308,6 +5317,15 @@ riscv_conditional_register_usage (void) for (int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++) call_used_regs[regno] = 1; } + + if (!TARGET_VECTOR) + { + for (int regno = V_REG_FIRST; regno <= V_REG_LAST; regno++) + call_used_regs[regno] = 1; + + fixed_regs[VTYPE_REGNUM] = call_used_regs[VTYPE_REGNUM] = 1; + fixed_regs[VL_REGNUM] = call_used_regs[VL_REGNUM] = 1; + } } /* Return a register priority for hard reg REGNO. */ @@ -5903,6 +5921,9 @@ riscv_asan_shadow_offset (void) #undef TARGET_BUILTIN_DECL #define TARGET_BUILTIN_DECL riscv_builtin_decl +#undef TARGET_GIMPLE_FOLD_BUILTIN +#define TARGET_GIMPLE_FOLD_BUILTIN riscv_gimple_fold_builtin + #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN riscv_expand_builtin diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index b5abf9c45d0..9b0da73f3b5 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -27,6 +27,42 @@ riscv-vector.o: $(srcdir)/config/riscv/riscv-vector.cc $(COMPILE) $< $(POSTCOMPILE) +riscv-vector-builtins-functions.o: \ + $(srcdir)/config/riscv/riscv-vector-builtins-functions.cc \ + $(srcdir)/config/riscv/riscv-vector-builtins.def \ + $(srcdir)/config/riscv/riscv-vector-builtins-functions.def \ + $(srcdir)/config/riscv/vector-iterators.md \ + $(srcdir)/config/riscv/md-parser \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + $(TM_P_H) memmodel.h insn-codes.h $(OPTABS_H) $(RECOG_H) $(DIAGNOSTIC_H) \ + $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) fold-const.h $(GIMPLE_H) \ + gimple-iterator.h gimplify.h explow.h $(EMIT_RTL_H) tree-vector-builder.h \ + stor-layout.h $(REG_H) alias.h gimple-fold.h langhooks.h \ + stringpool.h \ + $(srcdir)/config/riscv/riscv-vector-builtins-functions.h + python3 $(srcdir)/config/riscv/md-parser \ + riscv-vector-builtins-iterators.def vector-iterators.md && \ + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/riscv/riscv-vector-builtins-functions.cc + +riscv-vector-builtins.o: \ + $(srcdir)/config/riscv/riscv-vector-builtins.cc \ + $(srcdir)/config/riscv/riscv-vector-builtins.def \ + $(srcdir)/config/riscv/riscv-vector-builtins-functions.def \ + $(srcdir)/config/riscv/vector-iterators.md \ + $(srcdir)/config/riscv/md-parser \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ + $(TM_P_H) memmodel.h insn-codes.h $(OPTABS_H) $(RECOG_H) $(DIAGNOSTIC_H) \ + $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) fold-const.h $(GIMPLE_H) \ + gimple-iterator.h gimplify.h explow.h $(EMIT_RTL_H) tree-vector-builder.h \ + stor-layout.h $(REG_H) alias.h gimple-fold.h langhooks.h \ + stringpool.h \ + $(srcdir)/config/riscv/riscv-vector-builtins.h \ + $(srcdir)/config/riscv/riscv-vector-builtins-functions.h \ + riscv-vector-builtins-functions.o + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/riscv/riscv-vector-builtins.cc + PASSES_EXTRA += $(srcdir)/config/riscv/riscv-passes.def $(common_out_file): $(srcdir)/config/riscv/riscv-cores.def \ diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md new file mode 100644 index 00000000000..450e20c44ce --- /dev/null +++ b/gcc/config/riscv/vector-iterators.md @@ -0,0 +1,19 @@ +;; Machine description for RISCV architecture. +;; Copyright (C) 2022-2022 Free Software Foundation, Inc. +;; Contributed by Juzhe Zhong (juzhe.zh...@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 +;; <http://www.gnu.org/licenses/>. \ No newline at end of file -- 2.36.1