From: juzhe.zhong@rivai.ai
To: gcc-patches@gcc.gnu.org
Cc: kito.cheng@gmail.com, palmer@dabbelt.com, juzhe.zhong@rivai.ai
Subject: [PATCH 02/21] Add RVV intrinsic framework
Date: Tue, 31 May 2022 16:49:53 +0800 [thread overview]
Message-ID: <20220531085012.269719-3-juzhe.zhong@rivai.ai> (raw)
In-Reply-To: <20220531085012.269719-1-juzhe.zhong@rivai.ai>
From: zhongjuzhe <juzhe.zhong@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.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
+# <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.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
+<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.zhong@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.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
+ <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.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
+ <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.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
+<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.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
+ <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.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
+;; <http://www.gnu.org/licenses/>.
\ No newline at end of file
--
2.36.1
next prev parent reply other threads:[~2022-05-31 8:50 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-31 8:49 [PATCH 00/21] *** Add RVV (RISC-V 'V' Extension) support *** juzhe.zhong
2022-05-31 8:49 ` [PATCH 01/21] Add RVV modes and support scalable vector juzhe.zhong
2022-05-31 8:49 ` juzhe.zhong [this message]
2022-05-31 8:49 ` [PATCH 03/21] Add RVV datatypes juzhe.zhong
2022-05-31 8:49 ` [PATCH 04/21] Add RVV intrinsic enable #pragma riscv intrinsic "vector" and introduce RVV header "riscv_vector.h" juzhe.zhong
2022-05-31 8:49 ` [PATCH 05/21] Add RVV configuration intrinsic juzhe.zhong
2022-05-31 8:49 ` [PATCH 06/21] Add insert-vsetvl pass juzhe.zhong
2022-05-31 8:49 ` [PATCH 07/21] Add register spilling support juzhe.zhong
2022-05-31 8:49 ` [PATCH 08/21] Add poly manipulation juzhe.zhong
2022-05-31 8:50 ` [PATCH 09/21] Add misc function intrinsic support juzhe.zhong
2022-05-31 8:50 ` [PATCH 11/21] Add calling function support juzhe.zhong
2022-05-31 8:50 ` [PATCH 12/21] Add set get intrinsic support juzhe.zhong
2022-05-31 8:50 ` [PATCH 13/21] Adjust scalable frame and full testcases juzhe.zhong
2022-05-31 8:50 ` [PATCH 15/21] Add integer intrinsics juzhe.zhong
2022-05-31 8:50 ` [PATCH 18/21] Add rest intrinsic support juzhe.zhong
2022-05-31 16:51 ` [PATCH 00/21] *** Add RVV (RISC-V 'V' Extension) support *** Palmer Dabbelt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220531085012.269719-3-juzhe.zhong@rivai.ai \
--to=juzhe.zhong@rivai.ai \
--cc=gcc-patches@gcc.gnu.org \
--cc=kito.cheng@gmail.com \
--cc=palmer@dabbelt.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).