RISC-V: Add RVV intrinsic basic framework.

gcc/ChangeLog:

	* config.gcc: Add gt files since function_instance is GTY ((user)).
	* config/riscv/riscv-builtins.cc (riscv_init_builtins): Add RVV intrinsic framework.
	(riscv_builtin_decl): Ditto.
	(riscv_expand_builtin): Ditto.
	* config/riscv/riscv-protos.h (builtin_decl): New function.
	(expand_builtin): Ditto.
	(enum riscv_builtin_class): New enum to classify RVV intrinsic and RISC-V general built-in.
	* config/riscv/riscv-vector-builtins.cc (class GTY): New declaration.
	(struct registered_function_hasher): New struct.
	(DEF_RVV_OP_TYPE): New macro.
	(DEF_RVV_TYPE): Ditto.
	(DEF_RVV_PRED_TYPE): Ditto.
	(GTY): New declaration.
	(add_attribute): New function.
	(check_required_extensions): Ditto.
	(rvv_arg_type_info::get_tree_type): Ditto.
	(function_instance::function_instance): Ditto.
	(function_instance::operator==): Ditto.
	(function_instance::any_type_float_p): Ditto.
	(function_instance::get_return_type): Ditto.
	(function_instance::get_arg_type): Ditto.
	(function_instance::hash): Ditto.
	(function_instance::call_properties): Ditto.
	(function_instance::reads_global_state_p): Ditto.
	(function_instance::modifies_global_state_p): Ditto.
	(function_instance::could_trap_p): Ditto.
	(function_builder::function_builder): Ditto.
	(function_builder::~function_builder): Ditto.
	(function_builder::allocate_argument_types): Ditto.
	(function_builder::register_function_group): Ditto.
	(function_builder::append_name): Ditto.
	(function_builder::finish_name): Ditto.
	(function_builder::get_attributes): Ditto.
	(function_builder::add_function): Ditto.
	(function_builder::add_unique_function): Ditto.
	(function_call_info::function_call_info): Ditto.
	(function_expander::function_expander): Ditto.
	(function_expander::add_input_operand): Ditto.
	(function_expander::generate_insn): Ditto.
	(registered_function_hasher::hash): Ditto.
	(registered_function_hasher::equal): Ditto.
	(builtin_decl): Ditto.
	(expand_builtin): Ditto.
	(gt_ggc_mx): Define for using GCC garbage collect.
	(gt_pch_nx): Define for using GCC garbage collect.
	* config/riscv/riscv-vector-builtins.def (DEF_RVV_OP_TYPE): New macro.
	(DEF_RVV_PRED_TYPE): Ditto.
	(vbool64_t): Add suffix.
	(vbool32_t): Ditto.
	(vbool16_t): Ditto.
	(vbool8_t): Ditto.
	(vbool4_t): Ditto.
	(vbool2_t): Ditto.
	(vbool1_t): Ditto.
	(vint8mf8_t): Ditto.
	(vuint8mf8_t): Ditto.
	(vint8mf4_t): Ditto.
	(vuint8mf4_t): Ditto.
	(vint8mf2_t): Ditto.
	(vuint8mf2_t): Ditto.
	(vint8m1_t): Ditto.
	(vuint8m1_t): Ditto.
	(vint8m2_t): Ditto.
	(vuint8m2_t): Ditto.
	(vint8m4_t): Ditto.
	(vuint8m4_t): Ditto.
	(vint8m8_t): Ditto.
	(vuint8m8_t): Ditto.
	(vint16mf4_t): Ditto.
	(vuint16mf4_t): Ditto.
	(vint16mf2_t): Ditto.
	(vuint16mf2_t): Ditto.
	(vint16m1_t): Ditto.
	(vuint16m1_t): Ditto.
	(vint16m2_t): Ditto.
	(vuint16m2_t): Ditto.
	(vint16m4_t): Ditto.
	(vuint16m4_t): Ditto.
	(vint16m8_t): Ditto.
	(vuint16m8_t): Ditto.
	(vint32mf2_t): Ditto.
	(vuint32mf2_t): Ditto.
	(vint32m1_t): Ditto.
	(vuint32m1_t): Ditto.
	(vint32m2_t): Ditto.
	(vuint32m2_t): Ditto.
	(vint32m4_t): Ditto.
	(vuint32m4_t): Ditto.
	(vint32m8_t): Ditto.
	(vuint32m8_t): Ditto.
	(vint64m1_t): Ditto.
	(vuint64m1_t): Ditto.
	(vint64m2_t): Ditto.
	(vuint64m2_t): Ditto.
	(vint64m4_t): Ditto.
	(vuint64m4_t): Ditto.
	(vint64m8_t): Ditto.
	(vuint64m8_t): Ditto.
	(vfloat32mf2_t): Ditto.
	(vfloat32m1_t): Ditto.
	(vfloat32m2_t): Ditto.
	(vfloat32m4_t): Ditto.
	(vfloat32m8_t): Ditto.
	(vfloat64m1_t): Ditto.
	(vfloat64m2_t): Ditto.
	(vfloat64m4_t): Ditto.
	(vfloat64m8_t): Ditto.
	(vv): Ditto.
	(vx): Ditto.
	(v): Ditto.
	(wv): Ditto.
	(wx): Ditto.
	(x_x_v): Ditto.
	(vf2): Ditto.
	(vf4): Ditto.
	(vf8): Ditto.
	(vvm): Ditto.
	(vxm): Ditto.
	(x_x_w): Ditto.
	(v_v): Ditto.
	(v_x): Ditto.
	(vs): Ditto.
	(mm): Ditto.
	(m): Ditto.
	(vf): Ditto.
	(vm): Ditto.
	(wf): Ditto.
	(vfm): Ditto.
	(v_f): Ditto.
	(ta): Ditto.
	(tu): Ditto.
	(ma): Ditto.
	(mu): Ditto.
	(tama): Ditto.
	(tamu): Ditto.
	(tuma): Ditto.
	(tumu): Ditto.
	(tam): Ditto.
	(tum): Ditto.
	* config/riscv/riscv-vector-builtins.h (GCC_RISCV_VECTOR_BUILTINS_H): New macro.
	(RVV_REQUIRE_RV64BIT): Ditto.
	(RVV_REQUIRE_ZVE64): Ditto.
	(RVV_REQUIRE_ELEN_FP_32): Ditto.
	(RVV_REQUIRE_ELEN_FP_64): Ditto.
	(enum operand_type_index): New enum.
	(DEF_RVV_OP_TYPE): New macro.
	(enum predication_type_index): New enum.
	(DEF_RVV_PRED_TYPE): New macro.
	(enum rvv_base_type): New enum.
	(struct rvv_builtin_suffixes): New struct.
	(struct rvv_arg_type_info): Ditto.
	(struct rvv_type_info): Ditto.
	(struct rvv_op_info): Ditto.
	(class registered_function): New class.
	(class function_base): Ditto.
	(class function_shape): Ditto.
	(struct function_group_info): New struct.
	(class GTY): New class.
	(class function_builder): Ditto.
	(class function_call_info): Ditto.
	(function_call_info::function_returns_void_p): New function.
	(class function_expander): New class.
	(function_instance::operator!=): New function.
	(function_expander::expand): Ditto.
	(function_expander::add_input_operand): Ditto.
	(function_base::call_properties): Ditto.
This commit is contained in:
Ju-Zhe Zhong 2022-10-17 16:20:43 +08:00 committed by Kito Cheng
parent 4e7ec7dbbb
commit cbd505700e
6 changed files with 1064 additions and 80 deletions

View file

@ -520,6 +520,8 @@ riscv*)
extra_objs="${extra_objs} riscv-vector-builtins.o"
d_target_objs="riscv-d.o"
extra_headers="riscv_vector.h"
target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc"
target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.h"
;;
rs6000*-*-*)
extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"

View file

@ -223,7 +223,10 @@ riscv_init_builtins (void)
{
tree type = riscv_build_function_type (d->prototype);
riscv_builtin_decls[i]
= add_builtin_function (d->name, type, i, BUILT_IN_MD, NULL, NULL);
= add_builtin_function (d->name, type,
(i << RISCV_BUILTIN_SHIFT)
+ RISCV_BUILTIN_GENERAL,
BUILT_IN_MD, NULL, NULL);
riscv_builtin_decl_index[d->icode] = i;
}
}
@ -234,9 +237,18 @@ riscv_init_builtins (void)
tree
riscv_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
{
if (code >= ARRAY_SIZE (riscv_builtins))
return error_mark_node;
return riscv_builtin_decls[code];
unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
switch (code & RISCV_BUILTIN_CLASS)
{
case RISCV_BUILTIN_GENERAL:
if (subcode >= ARRAY_SIZE (riscv_builtins))
return error_mark_node;
return riscv_builtin_decls[subcode];
case RISCV_BUILTIN_VECTOR:
return riscv_vector::builtin_decl (subcode, initialize_p);
}
return error_mark_node;
}
/* Take argument ARGNO from EXP's argument list and convert it into
@ -303,15 +315,23 @@ riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
const struct riscv_builtin_description *d = &riscv_builtins[fcode];
switch (d->builtin_type)
unsigned int subcode = fcode >> RISCV_BUILTIN_SHIFT;
switch (fcode & RISCV_BUILTIN_CLASS)
{
case RISCV_BUILTIN_DIRECT:
return riscv_expand_builtin_direct (d->icode, target, exp, true);
case RISCV_BUILTIN_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 ();

View file

@ -124,6 +124,23 @@ extern const char *mangle_builtin_type (const_tree);
extern bool verify_type_context (location_t, type_context_kind, const_tree, bool);
#endif
extern void handle_pragma_vector (void);
extern tree builtin_decl (unsigned, bool);
extern rtx expand_builtin (unsigned int, tree, rtx);
}
/* We classify builtin types into two classes:
1. General builtin class which is defined in riscv_builtins.
2. Vector builtin class which is a special builtin architecture
that implement intrinsic short into "pragma". */
enum riscv_builtin_class
{
RISCV_BUILTIN_GENERAL,
RISCV_BUILTIN_VECTOR
};
const unsigned int RISCV_BUILTIN_SHIFT = 1;
/* Mask that selects the riscv_builtin_class part of a function code. */
const unsigned int RISCV_BUILTIN_CLASS = (1 << RISCV_BUILTIN_SHIFT) - 1;
#endif /* ! GCC_RISCV_PROTOS_H */

View file

@ -66,13 +66,55 @@ struct vector_type_info
const char *mangled_name;
};
/* Information about each RVV type. */
/* Describes a function decl. */
class GTY (()) registered_function
{
public:
function_instance GTY ((skip)) instance;
/* The decl itself. */
tree GTY ((skip)) decl;
};
/* Hash traits for registered_function. */
struct registered_function_hasher : nofree_ptr_hash<registered_function>
{
typedef function_instance compare_type;
static hashval_t hash (value_type);
static bool equal (value_type, const compare_type &);
};
/* Static information about each RVV type. */
static CONSTEXPR const vector_type_info vector_types[] = {
#define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, ARGS...) \
{#NAME, #ABI_NAME, "u" #NCHARS #ABI_NAME},
#include "riscv-vector-builtins.def"
};
/* Static information about operand suffix for each RVV type. */
const char *const operand_suffixes[NUM_OP_TYPES] = {
"", /* OP_TYPE_none. */
#define DEF_RVV_OP_TYPE(NAME) "_" # NAME,
#include "riscv-vector-builtins.def"
};
/* Static information about type suffix for each RVV type. */
const rvv_builtin_suffixes type_suffixes[NUM_VECTOR_TYPES + 1] = {
#define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \
VECTOR_MODE_MIN_VLEN_32, VECTOR_SUFFIX, SCALAR_SUFFIX, \
VSETVL_SUFFIX) \
{#VECTOR_SUFFIX, #SCALAR_SUFFIX, #VSETVL_SUFFIX},
#include "riscv-vector-builtins.def"
};
/* Static information about predication suffix for each RVV type. */
const char *const predication_suffixes[NUM_PRED_TYPES] = {
"", /* PRED_TYPE_none. */
#define DEF_RVV_PRED_TYPE(NAME) "_" # NAME,
#include "riscv-vector-builtins.def"
};
/* The RVV types, with their built-in
"__rvv..._t" name. Allow an index of NUM_VECTOR_TYPES, which always
yields a null tree. */
@ -82,6 +124,14 @@ static GTY (()) tree abi_vector_types[NUM_VECTOR_TYPES + 1];
extern GTY (()) rvv_builtin_types_t builtin_types[NUM_VECTOR_TYPES + 1];
rvv_builtin_types_t builtin_types[NUM_VECTOR_TYPES + 1];
/* The list of all registered function decls, indexed by code. */
static GTY (()) vec<registered_function *, va_gc> *registered_functions;
/* All registered function decls, hashed on the function_instance
that they implement. This is used for looking up implementations of
overloaded functions. */
static hash_table<registered_function_hasher> *function_table;
/* RAII class for enabling enough RVV features to define the built-in
types and implement the riscv_vector.h pragma.
@ -118,6 +168,13 @@ rvv_switcher::~rvv_switcher ()
sizeof (have_regs_of_mode));
}
/* Add attribute NAME to ATTRS. */
static tree
add_attribute (const char *name, tree attrs)
{
return tree_cons (get_identifier (name), NULL_TREE, attrs);
}
/* Add type attributes to builtin type tree, currently only the mangled name. */
static void
add_vector_type_attribute (tree type, const char *mangled_name)
@ -215,6 +272,7 @@ static void
register_vector_type (vector_type_index type)
{
tree vectype = abi_vector_types[type];
/* When vectype is NULL, the corresponding builtin type
is disabled according to '-march'. */
if (!vectype)
@ -237,6 +295,386 @@ register_vector_type (vector_type_index type)
builtin_types[type].vector_ptr = build_pointer_type (vectype);
}
/* Check whether all the RVV_REQUIRE_* values in REQUIRED_EXTENSIONS are
enabled. */
static bool
check_required_extensions (uint64_t required_extensions)
{
uint64_t riscv_isa_flags = 0;
if (TARGET_VECTOR_ELEN_FP_32)
riscv_isa_flags |= RVV_REQUIRE_ELEN_FP_32;
if (TARGET_VECTOR_ELEN_FP_64)
riscv_isa_flags |= RVV_REQUIRE_ELEN_FP_64;
if (TARGET_MIN_VLEN > 32)
riscv_isa_flags |= RVV_REQUIRE_ZVE64;
if (TARGET_64BIT)
riscv_isa_flags |= RVV_REQUIRE_RV64BIT;
uint64_t missing_extensions = required_extensions & ~riscv_isa_flags;
if (missing_extensions != 0)
return false;
return true;
}
tree
rvv_arg_type_info::get_tree_type (vector_type_index type_idx) const
{
switch (base_type)
{
case RVV_BASE_vector:
return builtin_types[type_idx].vector;
case RVV_BASE_scalar:
return builtin_types[type_idx].scalar;
case RVV_BASE_vector_ptr:
return builtin_types[type_idx].vector_ptr;
case RVV_BASE_scalar_ptr:
return builtin_types[type_idx].scalar_ptr;
case RVV_BASE_scalar_const_ptr:
return builtin_types[type_idx].scalar_const_ptr;
case RVV_BASE_void:
return void_type_node;
case RVV_BASE_size:
return size_type_node;
case RVV_BASE_ptrdiff:
return ptrdiff_type_node;
case RVV_BASE_unsigned_long:
return long_unsigned_type_node;
case RVV_BASE_long:
return long_integer_type_node;
default:
gcc_unreachable ();
}
}
function_instance::function_instance (const char *base_name_in,
const function_base *base_in,
const function_shape *shape_in,
rvv_type_info type_in,
predication_type_index pred_in,
const rvv_op_info *op_info_in)
: base_name (base_name_in), base (base_in), shape (shape_in), type (type_in),
pred (pred_in), op_info (op_info_in)
{
}
bool
function_instance::operator== (const function_instance &other) const
{
for (unsigned int i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i)
if (op_info->args[i].base_type != other.op_info->args[i].base_type)
return false;
return (base == other.base && shape == other.shape
&& type.index == other.type.index && op_info->op == other.op_info->op
&& pred == other.pred
&& op_info->ret.base_type == other.op_info->ret.base_type);
}
bool
function_instance::any_type_float_p () const
{
if (FLOAT_MODE_P (TYPE_MODE (get_return_type ())))
return true;
for (int i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i)
if (FLOAT_MODE_P (TYPE_MODE (get_arg_type (i))))
return true;
return false;
}
tree
function_instance::get_return_type () const
{
return op_info->ret.get_tree_type (type.index);
}
tree
function_instance::get_arg_type (unsigned opno) const
{
return op_info->args[opno].get_tree_type (type.index);
}
/* Return a hash code for a function_instance. */
hashval_t
function_instance::hash () const
{
inchash::hash h;
/* BASE uniquely determines BASE_NAME, so we don't need to hash both. */
h.add_ptr (base);
h.add_ptr (shape);
h.add_int (type.index);
h.add_int (op_info->op);
h.add_int (pred);
h.add_int (op_info->ret.base_type);
for (unsigned int i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i)
h.add_int (op_info->args[i].base_type);
return h.end ();
}
/* Return a set of CP_* flags that describe what the function could do,
taking the command-line flags into account. */
unsigned int
function_instance::call_properties () const
{
unsigned int flags = base->call_properties (*this);
/* -fno-trapping-math means that we can assume any FP exceptions
are not user-visible. */
if (!flag_trapping_math)
flags &= ~CP_RAISE_FP_EXCEPTIONS;
return flags;
}
/* Return true if calls to the function could read some form of
global state. */
bool
function_instance::reads_global_state_p () const
{
unsigned int flags = call_properties ();
/* Preserve any dependence on rounding mode, flush to zero mode, etc.
There is currently no way of turning this off; in particular,
-fno-rounding-math (which is the default) means that we should make
the usual assumptions about rounding mode, which for intrinsics means
acting as the instructions do. */
if (flags & CP_READ_FPCR)
return true;
/* Handle direct reads of global state. */
return flags & (CP_READ_MEMORY | CP_READ_CSR);
}
/* Return true if calls to the function could modify some form of
global state. */
bool
function_instance::modifies_global_state_p () const
{
unsigned int flags = call_properties ();
/* Preserve any exception state written back to the FPCR,
unless -fno-trapping-math says this is unnecessary. */
if (flags & CP_RAISE_FP_EXCEPTIONS)
return true;
/* Handle direct modifications of global state. */
return flags & (CP_WRITE_MEMORY | CP_WRITE_CSR);
}
/* Return true if calls to the function could raise a signal. */
bool
function_instance::could_trap_p () const
{
unsigned int flags = call_properties ();
/* Handle functions that could raise SIGFPE. */
if (flags & CP_RAISE_FP_EXCEPTIONS)
return true;
/* Handle functions that could raise SIGBUS or SIGSEGV. */
if (flags & (CP_READ_MEMORY | CP_WRITE_MEMORY))
return true;
return false;
}
function_builder::function_builder ()
{
m_direct_overloads = lang_GNU_CXX ();
gcc_obstack_init (&m_string_obstack);
}
function_builder::~function_builder ()
{
obstack_free (&m_string_obstack, NULL);
}
/* Allocate arguments of the function. */
void
function_builder::allocate_argument_types (const function_instance &instance,
vec<tree> &argument_types) const
{
for (unsigned int i = 0;
instance.op_info->args[i].base_type != NUM_BASE_TYPES; ++i)
argument_types.quick_push (
instance.op_info->args[i].get_tree_type (instance.type.index));
}
/* Register all the functions in GROUP. */
void
function_builder::register_function_group (const function_group_info &group)
{
(*group.shape)->build (*this, group);
}
/* Add NAME to the end of the function name being built. */
void
function_builder::append_name (const char *name)
{
obstack_grow (&m_string_obstack, name, strlen (name));
}
/* Zero-terminate and complete the function name being built. */
char *
function_builder::finish_name ()
{
obstack_1grow (&m_string_obstack, 0);
return (char *) obstack_finish (&m_string_obstack);
}
/* Return the appropriate function attributes for INSTANCE. */
tree
function_builder::get_attributes (const function_instance &instance)
{
tree attrs = NULL_TREE;
if (!instance.modifies_global_state_p ())
{
if (instance.reads_global_state_p ())
attrs = add_attribute ("pure", attrs);
else
attrs = add_attribute ("const", attrs);
}
if (!flag_non_call_exceptions || !instance.could_trap_p ())
attrs = add_attribute ("nothrow", attrs);
return add_attribute ("leaf", attrs);
}
/* Add a function called NAME with type FNTYPE and attributes ATTRS.
INSTANCE describes what the function does. */
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
bool placeholder_p)
{
unsigned int code = vec_safe_length (registered_functions);
code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
/* We need to be able to generate placeholders to enusre that we have a
consistent numbering scheme for function codes between the C and C++
frontends, so that everything ties up in LTO.
Currently, tree-streamer-in.c:unpack_ts_function_decl_value_fields
validates that tree nodes returned by TARGET_BUILTIN_DECL are non-NULL and
some node other than error_mark_node. This is a holdover from when builtin
decls were streamed by code rather than by value.
Ultimately, we should be able to remove this validation of BUILT_IN_MD
nodes and remove the target hook. For now, however, we need to appease the
validation and return a non-NULL, non-error_mark_node node, so we
arbitrarily choose integer_zero_node. */
tree decl = placeholder_p
? integer_zero_node
: simulate_builtin_function_decl (input_location, name, fntype,
code, NULL, attrs);
registered_function &rfn = *ggc_alloc<registered_function> ();
rfn.instance = instance;
rfn.decl = decl;
vec_safe_push (registered_functions, &rfn);
return rfn;
}
/* Add a built-in function for INSTANCE, with the argument types given
by ARGUMENT_TYPES and the return type given by RETURN_TYPE. NAME is
the "full" name for C function. OVERLOAD_NAME is the "short" name for
C++ overloaded function. OVERLOAD_NAME can be nullptr because some
instance doesn't have C++ overloaded function. */
void
function_builder::add_unique_function (const function_instance &instance,
const function_shape *shape,
tree return_type,
vec<tree> &argument_types)
{
/* Do not add this function if it is invalid. */
if (!check_required_extensions (instance.type.required_extensions))
return;
/* Add the function under its full (unique) name. */
char *name = shape->get_name (*this, instance, false);
tree fntype
= build_function_type_array (return_type, argument_types.length (),
argument_types.address ());
tree attrs = get_attributes (instance);
registered_function &rfn
= add_function (instance, name, fntype, attrs, false);
/* Enter the function into the hash table. */
hashval_t hash = instance.hash ();
registered_function **rfn_slot
= function_table->find_slot_with_hash (instance, hash, INSERT);
gcc_assert (!*rfn_slot);
*rfn_slot = &rfn;
/* Also add the function under its overloaded alias, if we want
a separate decl for each instance of an overloaded function. */
char *overload_name = shape->get_name (*this, instance, true);
if (overload_name)
{
/* Attribute lists shouldn't be shared. */
tree attrs = get_attributes (instance);
bool placeholder_p = !m_direct_overloads;
add_function (instance, overload_name, fntype, attrs, placeholder_p);
}
obstack_free (&m_string_obstack, name);
}
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
: function_instance (instance_in), location (location_in), fndecl (fndecl_in)
{}
function_expander::function_expander (const function_instance &instance,
tree fndecl_in, tree exp_in,
rtx target_in)
: function_call_info (EXPR_LOCATION (exp_in), instance, fndecl_in),
exp (exp_in), target (target_in), opno (0)
{
if (!function_returns_void_p ())
create_output_operand (&m_ops[opno++], target, TYPE_MODE (TREE_TYPE (exp)));
}
/* Take argument ARGNO from EXP's argument list and convert it into
an expand operand. Store the operand in *M_OPS. */
void
function_expander::add_input_operand (unsigned argno)
{
tree arg = CALL_EXPR_ARG (exp, argno);
rtx x = expand_normal (arg);
add_input_operand (TYPE_MODE (TREE_TYPE (arg)), x);
}
/* Generate instruction ICODE, given that its operands have already
been added to M_OPS. Return the value of the first operand. */
rtx
function_expander::generate_insn (insn_code icode)
{
gcc_assert (opno == insn_data[icode].n_generator_args);
if (!maybe_expand_insn (icode, opno, m_ops))
{
error ("invalid argument to built-in function");
return NULL_RTX;
}
return function_returns_void_p () ? const0_rtx : m_ops[0].value;
}
inline hashval_t
registered_function_hasher::hash (value_type value)
{
return value->instance.hash ();
}
inline bool
registered_function_hasher::equal (value_type value, const compare_type &key)
{
return value->instance == key;
}
/* If TYPE is a built-in type defined by the RVV ABI, return the mangled name,
otherwise return NULL. */
const char *
@ -356,4 +794,39 @@ handle_pragma_vector ()
register_vector_type ((enum vector_type_index) type_i);
}
/* Return the function decl with RVV function subcode CODE, or error_mark_node
if no such function exists. */
tree
builtin_decl (unsigned int code, bool)
{
if (code >= vec_safe_length (registered_functions))
return error_mark_node;
return (*registered_functions)[code]->decl;
}
/* Expand a call to the RVV function with subcode CODE. EXP is the call
expression and TARGET is the preferred location for the result.
Return the value of the lhs. */
rtx
expand_builtin (unsigned int code, tree exp, rtx target)
{
registered_function &rfn = *(*registered_functions)[code];
return function_expander (rfn.instance, rfn.decl, exp, target).expand ();
}
} // end namespace riscv_vector
inline void
gt_ggc_mx (function_instance *)
{}
inline void
gt_pch_nx (function_instance *)
{}
inline void
gt_pch_nx (function_instance *, gt_pointer_operator, void *)
{}
#include "gt-riscv-vector-builtins.h"

View file

@ -19,181 +19,290 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* Use "DEF_RVV_TYPE" macro to define RVV datatype builtins.
1.The 1 argument is the name exposed to users.
1.The 'NAME' argument is the name exposed to users.
For example, "vint32m1_t".
2.The 2 argument is the length of ABI-name.
2.The 'NCHARS' argument is the length of ABI-name.
For example, length of "__rvv_int32m1_t" is 15.
3.The 3 argument is the ABI-name. For example, "__rvv_int32m1_t".
4.The 4 argument is associated scalar type which is used in
3.The 'ABI_NAME' argument is the ABI-name. For example, "__rvv_int32m1_t".
4.The 'SCALAR_TYPE' argument is associated scalar type which is used in
"build_vector_type_for_mode". For "vint32m1_t", we use "intSI_type_node" in
RV64. Otherwise, we use "long_integer_type_node".
5.The 5 and 6 argument are the machine modes of corresponding RVV type used
in "build_vector_type_for_mode". For "vint32m1_t", we use VNx2SImode when
TARGET_MIN_VLEN > 32. Otherwise the machine mode is VNx1SImode. */
5.The 'VECTOR_MODE' is the machine modes of corresponding RVV type used
in "build_vector_type_for_mode" when TARGET_MIN_VLEN > 32.
For example: VECTOR_MODE = VNx2SI for "vint32m1_t".
6.The 'VECTOR_MODE_MIN_VLEN_32' is the machine modes of corresponding RVV
type used in "build_vector_type_for_mode" when TARGET_MIN_VLEN = 32. For
example: VECTOR_MODE_MIN_VLEN_32 = VNx1SI for "vint32m1_t".
7.The 'VECTOR_SUFFIX' define mode suffix for vector type.
For example: type_suffixes[VECTOR_TYPE_vin32m1_t].vector = i32m1.
8.The 'SCALAR_SUFFIX' define mode suffix for scalar type.
For example: type_suffixes[VECTOR_TYPE_vin32m1_t].scalar = i32.
9.The 'VSETVL_SUFFIX' define mode suffix for vsetvli instruction.
For example: type_suffixes[VECTOR_TYPE_vin32m1_t].vsetvl = e32m1.
*/
#ifndef DEF_RVV_TYPE
#define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \
VECTOR_MODE_MIN_VLEN_32)
VECTOR_MODE_MIN_VLEN_32, VECTOR_SUFFIX, SCALAR_SUFFIX, \
VSETVL_SUFFIX)
#endif
/* Use "DEF_RVV_OP_TYPE" macro to define RVV operand types.
The 'NAME' will be concatenated into intrinsic function name. */
#ifndef DEF_RVV_OP_TYPE
#define DEF_RVV_OP_TYPE(NAME)
#endif
/* Use "DEF_RVV_PRED_TYPE" macro to define RVV predication types.
The 'NAME' will be concatenated into intrinsic function name. */
#ifndef DEF_RVV_PRED_TYPE
#define DEF_RVV_PRED_TYPE(NAME)
#endif
/* SEW/LMUL = 64:
Only enable when TARGET_MIN_VLEN > 32 and machine mode = VNx1BImode. */
DEF_RVV_TYPE (vbool64_t, 14, __rvv_bool64_t, boolean, VNx1BI, VOID)
DEF_RVV_TYPE (vbool64_t, 14, __rvv_bool64_t, boolean, VNx1BI, VOID, _b64, , )
/* SEW/LMUL = 32:
Machine mode = VNx2BImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx1BImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vbool32_t, 14, __rvv_bool32_t, boolean, VNx2BI, VNx1BI)
DEF_RVV_TYPE (vbool32_t, 14, __rvv_bool32_t, boolean, VNx2BI, VNx1BI, _b32, , )
/* SEW/LMUL = 16:
Machine mode = VNx2BImode when TARGET_MIN_VLEN = 32.
Machine mode = VNx4BImode when TARGET_MIN_VLEN > 32. */
DEF_RVV_TYPE (vbool16_t, 14, __rvv_bool16_t, boolean, VNx4BI, VNx2BI)
DEF_RVV_TYPE (vbool16_t, 14, __rvv_bool16_t, boolean, VNx4BI, VNx2BI, _b16, , )
/* SEW/LMUL = 8:
Machine mode = VNx8BImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx4BImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vbool8_t, 13, __rvv_bool8_t, boolean, VNx8BI, VNx4BI)
DEF_RVV_TYPE (vbool8_t, 13, __rvv_bool8_t, boolean, VNx8BI, VNx4BI, _b8, , )
/* SEW/LMUL = 4:
Machine mode = VNx16BImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx8BImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vbool4_t, 13, __rvv_bool4_t, boolean, VNx16BI, VNx8BI)
DEF_RVV_TYPE (vbool4_t, 13, __rvv_bool4_t, boolean, VNx16BI, VNx8BI, _b4, , )
/* SEW/LMUL = 2:
Machine mode = VNx32BImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx16BImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vbool2_t, 13, __rvv_bool2_t, boolean, VNx32BI, VNx16BI)
DEF_RVV_TYPE (vbool2_t, 13, __rvv_bool2_t, boolean, VNx32BI, VNx16BI, _b2, , )
/* SEW/LMUL = 1:
Machine mode = VNx64BImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx32BImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vbool1_t, 13, __rvv_bool1_t, boolean, VNx64BI, VNx32BI)
DEF_RVV_TYPE (vbool1_t, 13, __rvv_bool1_t, boolean, VNx64BI, VNx32BI, _b1, , )
/* LMUL = 1/8:
Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1QImode. */
DEF_RVV_TYPE (vint8mf8_t, 15, __rvv_int8mf8_t, intQI, VNx1QI, VOID)
DEF_RVV_TYPE (vuint8mf8_t, 16, __rvv_uint8mf8_t, unsigned_intQI, VNx1QI, VOID)
DEF_RVV_TYPE (vint8mf8_t, 15, __rvv_int8mf8_t, intQI, VNx1QI, VOID, _i8mf8, _i8,
_e8mf8)
DEF_RVV_TYPE (vuint8mf8_t, 16, __rvv_uint8mf8_t, unsigned_intQI, VNx1QI, VOID,
_u8mf8, _u8, _e8mf8)
/* LMUL = 1/4:
Machine mode = VNx2QImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx1QImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint8mf4_t, 15, __rvv_int8mf4_t, intQI, VNx2QI, VNx1QI)
DEF_RVV_TYPE (vuint8mf4_t, 16, __rvv_uint8mf4_t, unsigned_intQI, VNx2QI, VNx1QI)
DEF_RVV_TYPE (vint8mf4_t, 15, __rvv_int8mf4_t, intQI, VNx2QI, VNx1QI, _i8mf4,
_i8, _e8mf4)
DEF_RVV_TYPE (vuint8mf4_t, 16, __rvv_uint8mf4_t, unsigned_intQI, VNx2QI, VNx1QI,
_u8mf4, _u8, _e8mf4)
/* LMUL = 1/2:
Machine mode = VNx4QImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx2QImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint8mf2_t, 15, __rvv_int8mf2_t, intQI, VNx4QI, VNx2QI)
DEF_RVV_TYPE (vuint8mf2_t, 16, __rvv_uint8mf2_t, unsigned_intQI, VNx4QI, VNx2QI)
DEF_RVV_TYPE (vint8mf2_t, 15, __rvv_int8mf2_t, intQI, VNx4QI, VNx2QI, _i8mf2,
_i8, _e8mf2)
DEF_RVV_TYPE (vuint8mf2_t, 16, __rvv_uint8mf2_t, unsigned_intQI, VNx4QI, VNx2QI,
_u8mf2, _u8, _e8mf2)
/* LMUL = 1:
Machine mode = VNx8QImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx4QImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint8m1_t, 14, __rvv_int8m1_t, intQI, VNx8QI, VNx4QI)
DEF_RVV_TYPE (vuint8m1_t, 15, __rvv_uint8m1_t, unsigned_intQI, VNx8QI, VNx4QI)
DEF_RVV_TYPE (vint8m1_t, 14, __rvv_int8m1_t, intQI, VNx8QI, VNx4QI, _i8m1, _i8,
_e8m1)
DEF_RVV_TYPE (vuint8m1_t, 15, __rvv_uint8m1_t, unsigned_intQI, VNx8QI, VNx4QI,
_u8m1, _u8, _e8m1)
/* LMUL = 2:
Machine mode = VNx16QImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx8QImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint8m2_t, 14, __rvv_int8m2_t, intQI, VNx16QI, VNx8QI)
DEF_RVV_TYPE (vuint8m2_t, 15, __rvv_uint8m2_t, unsigned_intQI, VNx16QI, VNx8QI)
DEF_RVV_TYPE (vint8m2_t, 14, __rvv_int8m2_t, intQI, VNx16QI, VNx8QI, _i8m2, _i8,
_e8m2)
DEF_RVV_TYPE (vuint8m2_t, 15, __rvv_uint8m2_t, unsigned_intQI, VNx16QI, VNx8QI,
_u8m2, _u8, _e8m2)
/* LMUL = 4:
Machine mode = VNx32QImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx16QImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint8m4_t, 14, __rvv_int8m4_t, intQI, VNx32QI, VNx16QI)
DEF_RVV_TYPE (vuint8m4_t, 15, __rvv_uint8m4_t, unsigned_intQI, VNx32QI, VNx16QI)
DEF_RVV_TYPE (vint8m4_t, 14, __rvv_int8m4_t, intQI, VNx32QI, VNx16QI, _i8m4,
_i8, _e8m4)
DEF_RVV_TYPE (vuint8m4_t, 15, __rvv_uint8m4_t, unsigned_intQI, VNx32QI, VNx16QI,
_u8m4, _u8, _e8m4)
/* LMUL = 8:
Machine mode = VNx64QImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx32QImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint8m8_t, 14, __rvv_int8m8_t, intQI, VNx64QI, VNx32QI)
DEF_RVV_TYPE (vuint8m8_t, 15, __rvv_uint8m8_t, unsigned_intQI, VNx64QI, VNx32QI)
DEF_RVV_TYPE (vint8m8_t, 14, __rvv_int8m8_t, intQI, VNx64QI, VNx32QI, _i8m8,
_i8, _e8m8)
DEF_RVV_TYPE (vuint8m8_t, 15, __rvv_uint8m8_t, unsigned_intQI, VNx64QI, VNx32QI,
_u8m8, _u8, _e8m8)
/* LMUL = 1/4:
Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1HImode. */
DEF_RVV_TYPE (vint16mf4_t, 16, __rvv_int16mf4_t, intHI, VNx1HI, VOID)
DEF_RVV_TYPE (vuint16mf4_t, 17, __rvv_uint16mf4_t, unsigned_intHI, VNx1HI, VOID)
DEF_RVV_TYPE (vint16mf4_t, 16, __rvv_int16mf4_t, intHI, VNx1HI, VOID, _i16mf4,
_i16, _e16mf4)
DEF_RVV_TYPE (vuint16mf4_t, 17, __rvv_uint16mf4_t, unsigned_intHI, VNx1HI, VOID,
_u16mf4, _u16, _e16mf4)
/* LMUL = 1/2:
Machine mode = VNx2HImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx1HImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint16mf2_t, 16, __rvv_int16mf2_t, intHI, VNx2HI, VNx1HI)
DEF_RVV_TYPE (vint16mf2_t, 16, __rvv_int16mf2_t, intHI, VNx2HI, VNx1HI, _i16mf2,
_i16, _e16mf2)
DEF_RVV_TYPE (vuint16mf2_t, 17, __rvv_uint16mf2_t, unsigned_intHI, VNx2HI,
VNx1HI)
VNx1HI, _u16mf2, _u16, _e16mf2)
/* LMUL = 1:
Machine mode = VNx4HImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx2HImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint16m1_t, 15, __rvv_int16m1_t, intHI, VNx4HI, VNx2HI)
DEF_RVV_TYPE (vuint16m1_t, 16, __rvv_uint16m1_t, unsigned_intHI, VNx4HI, VNx2HI)
DEF_RVV_TYPE (vint16m1_t, 15, __rvv_int16m1_t, intHI, VNx4HI, VNx2HI, _i16m1,
_i16, _e16m1)
DEF_RVV_TYPE (vuint16m1_t, 16, __rvv_uint16m1_t, unsigned_intHI, VNx4HI, VNx2HI,
_u16m1, _u16, _e16m1)
/* LMUL = 2:
Machine mode = VNx8HImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx4HImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint16m2_t, 15, __rvv_int16m2_t, intHI, VNx8HI, VNx4HI)
DEF_RVV_TYPE (vuint16m2_t, 16, __rvv_uint16m2_t, unsigned_intHI, VNx8HI, VNx4HI)
DEF_RVV_TYPE (vint16m2_t, 15, __rvv_int16m2_t, intHI, VNx8HI, VNx4HI, _i16m2,
_i16, _e16m2)
DEF_RVV_TYPE (vuint16m2_t, 16, __rvv_uint16m2_t, unsigned_intHI, VNx8HI, VNx4HI,
_u16m2, _u16, _e16m2)
/* LMUL = 4:
Machine mode = VNx16HImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx8HImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint16m4_t, 15, __rvv_int16m4_t, intHI, VNx16HI, VNx8HI)
DEF_RVV_TYPE (vint16m4_t, 15, __rvv_int16m4_t, intHI, VNx16HI, VNx8HI, _i16m4,
_i16, _e16m4)
DEF_RVV_TYPE (vuint16m4_t, 16, __rvv_uint16m4_t, unsigned_intHI, VNx16HI,
VNx8HI)
VNx8HI, _u16m4, _u16, _e16m4)
/* LMUL = 8:
Machine mode = VNx32HImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx16HImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint16m8_t, 15, __rvv_int16m8_t, intHI, VNx32HI, VNx16HI)
DEF_RVV_TYPE (vint16m8_t, 15, __rvv_int16m8_t, intHI, VNx32HI, VNx16HI, _i16m8,
_i16, _e16m8)
DEF_RVV_TYPE (vuint16m8_t, 16, __rvv_uint16m8_t, unsigned_intHI, VNx32HI,
VNx16HI)
VNx16HI, _u16m8, _u16, _e16m8)
/* LMUL = 1/2:
Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1SImode. */
DEF_RVV_TYPE (vint32mf2_t, 16, __rvv_int32mf2_t, int32, VNx1SI, VOID)
DEF_RVV_TYPE (vuint32mf2_t, 17, __rvv_uint32mf2_t, unsigned_int32, VNx1SI, VOID)
DEF_RVV_TYPE (vint32mf2_t, 16, __rvv_int32mf2_t, int32, VNx1SI, VOID, _i32mf2,
_i32, _e32mf2)
DEF_RVV_TYPE (vuint32mf2_t, 17, __rvv_uint32mf2_t, unsigned_int32, VNx1SI, VOID,
_u32mf2, _u32, _e32mf2)
/* LMUL = 1:
Machine mode = VNx2SImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx1SImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint32m1_t, 15, __rvv_int32m1_t, int32, VNx2SI, VNx1SI)
DEF_RVV_TYPE (vuint32m1_t, 16, __rvv_uint32m1_t, unsigned_int32, VNx2SI, VNx1SI)
DEF_RVV_TYPE (vint32m1_t, 15, __rvv_int32m1_t, int32, VNx2SI, VNx1SI, _i32m1,
_i32, _e32m1)
DEF_RVV_TYPE (vuint32m1_t, 16, __rvv_uint32m1_t, unsigned_int32, VNx2SI, VNx1SI,
_u32m1, _u32, _e32m1)
/* LMUL = 2:
Machine mode = VNx4SImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx2SImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint32m2_t, 15, __rvv_int32m2_t, int32, VNx4SI, VNx2SI)
DEF_RVV_TYPE (vuint32m2_t, 16, __rvv_uint32m2_t, unsigned_int32, VNx4SI, VNx2SI)
DEF_RVV_TYPE (vint32m2_t, 15, __rvv_int32m2_t, int32, VNx4SI, VNx2SI, _i32m2,
_i32, _e32m2)
DEF_RVV_TYPE (vuint32m2_t, 16, __rvv_uint32m2_t, unsigned_int32, VNx4SI, VNx2SI,
_u32m2, _u32, _e32m2)
/* LMUL = 4:
Machine mode = VNx8SImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx4SImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint32m4_t, 15, __rvv_int32m4_t, int32, VNx8SI, VNx4SI)
DEF_RVV_TYPE (vuint32m4_t, 16, __rvv_uint32m4_t, unsigned_int32, VNx8SI, VNx4SI)
DEF_RVV_TYPE (vint32m4_t, 15, __rvv_int32m4_t, int32, VNx8SI, VNx4SI, _i32m4,
_i32, _e32m4)
DEF_RVV_TYPE (vuint32m4_t, 16, __rvv_uint32m4_t, unsigned_int32, VNx8SI, VNx4SI,
_u32m4, _u32, _e32m4)
/* LMUL = 8:
Machine mode = VNx16SImode when TARGET_MIN_VLEN > 32.
Machine mode = VNx8SImode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vint32m8_t, 15, __rvv_int32m8_t, int32, VNx16SI, VNx8SI)
DEF_RVV_TYPE (vint32m8_t, 15, __rvv_int32m8_t, int32, VNx16SI, VNx8SI, _i32m8,
_i32, _e32m8)
DEF_RVV_TYPE (vuint32m8_t, 16, __rvv_uint32m8_t, unsigned_int32, VNx16SI,
VNx8SI)
VNx8SI, _u32m8, _u32, _e32m8)
/* SEW = 64:
Disable when TARGET_MIN_VLEN > 32. */
DEF_RVV_TYPE (vint64m1_t, 15, __rvv_int64m1_t, intDI, VNx1DI, VOID)
DEF_RVV_TYPE (vuint64m1_t, 16, __rvv_uint64m1_t, unsigned_intDI, VNx1DI, VOID)
DEF_RVV_TYPE (vint64m2_t, 15, __rvv_int64m2_t, intDI, VNx2DI, VOID)
DEF_RVV_TYPE (vuint64m2_t, 16, __rvv_uint64m2_t, unsigned_intDI, VNx2DI, VOID)
DEF_RVV_TYPE (vint64m4_t, 15, __rvv_int64m4_t, intDI, VNx4DI, VOID)
DEF_RVV_TYPE (vuint64m4_t, 16, __rvv_uint64m4_t, unsigned_intDI, VNx4DI, VOID)
DEF_RVV_TYPE (vint64m8_t, 15, __rvv_int64m8_t, intDI, VNx8DI, VOID)
DEF_RVV_TYPE (vuint64m8_t, 16, __rvv_uint64m8_t, unsigned_intDI, VNx8DI, VOID)
DEF_RVV_TYPE (vint64m1_t, 15, __rvv_int64m1_t, intDI, VNx1DI, VOID, _i64m1,
_i64, _e64m1)
DEF_RVV_TYPE (vuint64m1_t, 16, __rvv_uint64m1_t, unsigned_intDI, VNx1DI, VOID,
_u64m1, _u64, _e64m1)
DEF_RVV_TYPE (vint64m2_t, 15, __rvv_int64m2_t, intDI, VNx2DI, VOID, _i64m2,
_i64, _e64m2)
DEF_RVV_TYPE (vuint64m2_t, 16, __rvv_uint64m2_t, unsigned_intDI, VNx2DI, VOID,
_u64m2, _u64, _e64m2)
DEF_RVV_TYPE (vint64m4_t, 15, __rvv_int64m4_t, intDI, VNx4DI, VOID, _i64m4,
_i64, _e64m4)
DEF_RVV_TYPE (vuint64m4_t, 16, __rvv_uint64m4_t, unsigned_intDI, VNx4DI, VOID,
_u64m4, _u64, _e64m4)
DEF_RVV_TYPE (vint64m8_t, 15, __rvv_int64m8_t, intDI, VNx8DI, VOID, _i64m8,
_i64, _e64m8)
DEF_RVV_TYPE (vuint64m8_t, 16, __rvv_uint64m8_t, unsigned_intDI, VNx8DI, VOID,
_u64m8, _u64, _e64m8)
/* LMUL = 1/2:
Only enble when TARGET_MIN_VLEN > 32 and machine mode = VNx1SFmode. */
DEF_RVV_TYPE (vfloat32mf2_t, 18, __rvv_float32mf2_t, float, VNx1SF, VOID)
DEF_RVV_TYPE (vfloat32mf2_t, 18, __rvv_float32mf2_t, float, VNx1SF, VOID,
_f32mf2, _f32, _e32mf2)
/* LMUL = 1:
Machine mode = VNx2SFmode when TARGET_MIN_VLEN > 32.
Machine mode = VNx1SFmode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vfloat32m1_t, 17, __rvv_float32m1_t, float, VNx2SF, VNx1SF)
DEF_RVV_TYPE (vfloat32m1_t, 17, __rvv_float32m1_t, float, VNx2SF, VNx1SF,
_f32m1, _f32, _e32m1)
/* LMUL = 2:
Machine mode = VNx4SFmode when TARGET_MIN_VLEN > 32.
Machine mode = VNx2SFmode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vfloat32m2_t, 17, __rvv_float32m2_t, float, VNx4SF, VNx2SF)
DEF_RVV_TYPE (vfloat32m2_t, 17, __rvv_float32m2_t, float, VNx4SF, VNx2SF,
_f32m2, _f32, _e32m2)
/* LMUL = 4:
Machine mode = VNx8SFmode when TARGET_MIN_VLEN > 32.
Machine mode = VNx4SFmode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vfloat32m4_t, 17, __rvv_float32m4_t, float, VNx8SF, VNx4SF)
DEF_RVV_TYPE (vfloat32m4_t, 17, __rvv_float32m4_t, float, VNx8SF, VNx4SF,
_f32m4, _f32, _e32m4)
/* LMUL = 8:
Machine mode = VNx16SFmode when TARGET_MIN_VLEN > 32.
Machine mode = VNx8SFmode when TARGET_MIN_VLEN = 32. */
DEF_RVV_TYPE (vfloat32m8_t, 17, __rvv_float32m8_t, float, VNx16SF, VNx8SF)
DEF_RVV_TYPE (vfloat32m8_t, 17, __rvv_float32m8_t, float, VNx16SF, VNx8SF,
_f32m8, _f32, _e32m8)
/* SEW = 64:
Disable when TARGET_VECTOR_FP64. */
DEF_RVV_TYPE (vfloat64m1_t, 17, __rvv_float64m1_t, double, VNx1DF, VOID)
DEF_RVV_TYPE (vfloat64m2_t, 17, __rvv_float64m2_t, double, VNx2DF, VOID)
DEF_RVV_TYPE (vfloat64m4_t, 17, __rvv_float64m4_t, double, VNx4DF, VOID)
DEF_RVV_TYPE (vfloat64m8_t, 17, __rvv_float64m8_t, double, VNx8DF, VOID)
DEF_RVV_TYPE (vfloat64m1_t, 17, __rvv_float64m1_t, double, VNx1DF, VOID, _f64m1,
_f64, _e64m1)
DEF_RVV_TYPE (vfloat64m2_t, 17, __rvv_float64m2_t, double, VNx2DF, VOID, _f64m2,
_f64, _e64m2)
DEF_RVV_TYPE (vfloat64m4_t, 17, __rvv_float64m4_t, double, VNx4DF, VOID, _f64m4,
_f64, _e64m4)
DEF_RVV_TYPE (vfloat64m8_t, 17, __rvv_float64m8_t, double, VNx8DF, VOID, _f64m8,
_f64, _e64m8)
DEF_RVV_OP_TYPE (vv)
DEF_RVV_OP_TYPE (vx)
DEF_RVV_OP_TYPE (v)
DEF_RVV_OP_TYPE (wv)
DEF_RVV_OP_TYPE (wx)
DEF_RVV_OP_TYPE (x_x_v)
DEF_RVV_OP_TYPE (vf2)
DEF_RVV_OP_TYPE (vf4)
DEF_RVV_OP_TYPE (vf8)
DEF_RVV_OP_TYPE (vvm)
DEF_RVV_OP_TYPE (vxm)
DEF_RVV_OP_TYPE (x_x_w)
DEF_RVV_OP_TYPE (v_v)
DEF_RVV_OP_TYPE (v_x)
DEF_RVV_OP_TYPE (vs)
DEF_RVV_OP_TYPE (mm)
DEF_RVV_OP_TYPE (m)
DEF_RVV_OP_TYPE (vf)
DEF_RVV_OP_TYPE (vm)
DEF_RVV_OP_TYPE (wf)
DEF_RVV_OP_TYPE (vfm)
DEF_RVV_OP_TYPE (v_f)
DEF_RVV_PRED_TYPE (ta)
DEF_RVV_PRED_TYPE (tu)
DEF_RVV_PRED_TYPE (ma)
DEF_RVV_PRED_TYPE (mu)
DEF_RVV_PRED_TYPE (tama)
DEF_RVV_PRED_TYPE (tamu)
DEF_RVV_PRED_TYPE (tuma)
DEF_RVV_PRED_TYPE (tumu)
DEF_RVV_PRED_TYPE (m)
DEF_RVV_PRED_TYPE (tam)
DEF_RVV_PRED_TYPE (tum)
#undef DEF_RVV_PRED_TYPE
#undef DEF_RVV_OP_TYPE
#undef DEF_RVV_TYPE

View file

@ -21,8 +21,101 @@
#ifndef GCC_RISCV_VECTOR_BUILTINS_H
#define GCC_RISCV_VECTOR_BUILTINS_H
/* The full name of an RVV intrinsic function is the concatenation of:
- the base name ("vadd", etc.)
- the operand suffix ("_vv", "_vx", etc.)
- the type suffix ("_i32m1", "_i32mf2", etc.)
- the predication suffix ("_tamu", "_tumu", etc.)
Each piece of information is individually useful, so we retain this
classification throughout:
- function_base represents the base name.
- operand_type_index can be used as an index to get operand suffix.
- rvv_op_info can be used as an index to get argument suffix.
- predication_type_index can be used as an index to get predication suffix.
In addition to its unique full name, a function may have a shorter
overloaded alias. This alias removes pieces of the suffixes that
can be inferred from the arguments, such as by shortening the mode
suffix or dropping some of the type suffixes. The base name and the
predication suffix stay the same.
- The function_instance class describes contains all properties of each
individual function. Such these information will be used by
function_builder, function_base, function_shape, gimple_folder,
function_expander, etc.
- The function_builder class provides several helper function to add an
intrinsic function.
- The function_shape class describes how that instruction has been presented
at the language level:
1. Determine the function name for C and C++ overload function which can
be recognized by compiler at language level for each instruction
according to members of function_instance (base name, operand suffix,
type suffix, predication suffix, etc.).
2. Specify the arguments type and return type of each function to
describe how that instruction has presented at language level.
- The function_base describes how the underlying instruction behaves.
The static list of functions uses function_group to describe a group
of related functions. The function_builder class is responsible for
expanding this static description into a list of individual functions
and registering the associated built-in functions. function_instance
describes one of these individual functions in terms of the properties
described above.
The classes involved in compiling a function call are:
- function_resolver, which resolves an overloaded function call to a
specific function_instance and its associated function decl.
- function_checker, which checks whether the values of the arguments
conform to the RVV ISA specification.
- gimple_folder, which tries to fold a function call at the gimple level
- function_expander, which expands a function call into rtl instructions
function_resolver and function_checker operate at the language level
and so are associated with the function_shape. gimple_folder and
function_expander are concerned with the behavior of the function
and so are associated with the function_base. */
namespace riscv_vector {
/* Flags that describe what a function might do, in addition to reading
its arguments and returning a result. */
static const unsigned int CP_READ_FPCR = 1U << 0;
static const unsigned int CP_RAISE_FP_EXCEPTIONS = 1U << 1;
static const unsigned int CP_READ_MEMORY = 1U << 2;
static const unsigned int CP_WRITE_MEMORY = 1U << 3;
static const unsigned int CP_READ_CSR = 1U << 4;
static const unsigned int CP_WRITE_CSR = 1U << 5;
/* Bit values used to identify required extensions for RVV intrinsics. */
#define RVV_REQUIRE_RV64BIT (1 << 0) /* Require RV64. */
#define RVV_REQUIRE_ZVE64 (1 << 1) /* Require TARGET_MIN_VLEN > 32. */
#define RVV_REQUIRE_ELEN_FP_32 (1 << 2) /* Require FP ELEN >= 32. */
#define RVV_REQUIRE_ELEN_FP_64 (1 << 3) /* Require FP ELEN >= 64. */
/* Enumerates the RVV operand types. */
enum operand_type_index
{
OP_TYPE_none,
#define DEF_RVV_OP_TYPE(NAME) OP_TYPE_##NAME,
#include "riscv-vector-builtins.def"
NUM_OP_TYPES
};
/* Enumerates the RVV types, together called
"vector types" for brevity. */
enum vector_type_index
@ -32,6 +125,31 @@ enum vector_type_index
NUM_VECTOR_TYPES
};
/* Enumerates the RVV governing predication types. */
enum predication_type_index
{
PRED_TYPE_none,
#define DEF_RVV_PRED_TYPE(NAME) PRED_TYPE_##NAME,
#include "riscv-vector-builtins.def"
NUM_PRED_TYPES
};
/* Enumerates the RVV base types. */
enum rvv_base_type
{
RVV_BASE_vector,
RVV_BASE_scalar,
RVV_BASE_vector_ptr,
RVV_BASE_scalar_ptr,
RVV_BASE_scalar_const_ptr,
RVV_BASE_void,
RVV_BASE_size,
RVV_BASE_ptrdiff,
RVV_BASE_unsigned_long,
RVV_BASE_long,
NUM_BASE_TYPES
};
/* Builtin types that are used to register RVV intrinsics. */
struct GTY (()) rvv_builtin_types_t
{
@ -42,6 +160,251 @@ struct GTY (()) rvv_builtin_types_t
tree scalar_const_ptr;
};
/* Builtin suffix that are used to register RVV intrinsics. */
struct rvv_builtin_suffixes
{
const char *vector;
const char *scalar;
const char *vsetvl;
};
/* RVV Builtin argument information. */
struct rvv_arg_type_info
{
CONSTEXPR rvv_arg_type_info (rvv_base_type base_type_in)
: base_type (base_type_in)
{}
enum rvv_base_type base_type;
tree get_tree_type (vector_type_index) const;
};
/* Static information for each operand. */
struct rvv_type_info
{
enum vector_type_index index;
uint64_t required_extensions;
};
/* RVV Builtin operands information. */
struct rvv_op_info
{
const rvv_type_info *types;
const operand_type_index op;
rvv_arg_type_info ret;
const rvv_arg_type_info *args;
};
class registered_function;
class function_base;
class function_shape;
/* Static information about a set of functions. */
struct function_group_info
{
/* The base name, as a string. */
const char *base_name;
/* Describes the behavior associated with the function base name. */
const function_base *const *base;
/* The shape of the functions, as described above the class definition.
It's possible to have entries with the same base name but different
shapes. */
const function_shape *const *shape;
/* A list of the available operand types, predication types,
and of the available operand datatype.
The function supports every combination of the two.
The list of predication is terminated by two NUM_PRED_TYPES,
while the list of operand info is terminated by NUM_BASE_TYPES.
The list of these type suffix is lexicographically ordered based
on the index value. */
const predication_type_index *preds;
const rvv_op_info ops_infos;
};
class GTY ((user)) function_instance
{
public:
function_instance (const char *, const function_base *,
const function_shape *, rvv_type_info,
predication_type_index, const rvv_op_info *);
bool operator== (const function_instance &) const;
bool operator!= (const function_instance &) const;
hashval_t hash () const;
unsigned int call_properties () const;
bool reads_global_state_p () const;
bool modifies_global_state_p () const;
bool could_trap_p () const;
/* Return true if return type or arguments are floating point type. */
bool any_type_float_p () const;
tree get_return_type () const;
tree get_arg_type (unsigned opno) const;
/* The properties of the function. (The explicit "enum"s are required
for gengtype.) */
const char *base_name;
const function_base *base;
const function_shape *shape;
rvv_type_info type;
enum predication_type_index pred;
const rvv_op_info *op_info;
};
/* A class for building and registering function decls. */
class function_builder
{
public:
function_builder ();
~function_builder ();
void allocate_argument_types (const function_instance &, vec<tree> &) const;
void add_unique_function (const function_instance &, const function_shape *,
tree, vec<tree> &);
void register_function_group (const function_group_info &);
void append_name (const char *);
char *finish_name ();
private:
tree get_attributes (const function_instance &);
registered_function &add_function (const function_instance &, const char *,
tree, tree, bool);
/* True if we should create a separate decl for each instance of an
overloaded function, instead of using function_builder. */
bool m_direct_overloads;
/* Used for building up function names. */
obstack m_string_obstack;
};
/* A base class for handling calls to built-in functions. */
class function_call_info : public function_instance
{
public:
function_call_info (location_t, const function_instance &, tree);
bool function_returns_void_p ();
/* The location of the call. */
location_t location;
/* The FUNCTION_DECL that is being called. */
tree fndecl;
};
/* Return true if the function has no return value. */
inline bool
function_call_info::function_returns_void_p ()
{
return TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
}
/* A class for expanding a function call into RTL. */
class function_expander : public function_call_info
{
public:
function_expander (const function_instance &, tree, tree, rtx);
rtx expand ();
void add_input_operand (machine_mode, rtx);
void add_input_operand (unsigned argno);
rtx generate_insn (insn_code);
/* The function call expression. */
tree exp;
/* For functions that return a value, this is the preferred location
of that value. It could be null or could have a different mode
from the function return type. */
rtx target;
/* The number of the operands. */
int opno;
private:
/* Used to build up the operands to an instruction. */
struct expand_operand m_ops[MAX_RECOG_OPERANDS];
};
/* Provides information about a particular function base name, and handles
tasks related to the base name. */
class function_base
{
public:
/* Return a set of CP_* flags that describe what the function might do,
in addition to reading its arguments and returning a result. */
virtual unsigned int call_properties (const function_instance &) const;
/* Expand the given call into rtl. Return the result of the function,
or an arbitrary value if the function doesn't return a result. */
virtual rtx expand (function_expander &) const = 0;
};
/* Classifies functions into "shapes" base on:
- Base name of the intrinsic function.
- Operand types list.
- Argument type list.
- Predication type list. */
class function_shape
{
public:
/* Shape the function name according to function_instance. */
virtual char *get_name (function_builder &, const function_instance &,
bool) const
= 0;
/* Define all functions associated with the given group. */
virtual void build (function_builder &, const function_group_info &) const
= 0;
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
extern const rvv_builtin_suffixes type_suffixes[NUM_VECTOR_TYPES + 1];
extern const char *const predication_suffixes[NUM_PRED_TYPES];
extern rvv_builtin_types_t builtin_types[NUM_VECTOR_TYPES + 1];
inline bool
function_instance::operator!= (const function_instance &other) const
{
return !operator== (other);
}
/* Expand the call and return its lhs. */
inline rtx
function_expander::expand ()
{
return base->expand (*this);
}
/* Create op and add it into M_OPS and increase OPNO. */
inline void
function_expander::add_input_operand (machine_mode mode, rtx op)
{
create_input_operand (&m_ops[opno++], op, mode);
}
/* Default implementation of function_base::call_properties, with conservatively
correct behavior for floating-point instructions. */
inline unsigned int
function_base::call_properties (const function_instance &instance) const
{
unsigned int flags = 0;
if (instance.any_type_float_p ())
return flags | CP_READ_FPCR | CP_RAISE_FP_EXCEPTIONS;
return flags;
}
} // end namespace riscv_vector
#endif