public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
@ 2023-09-11  7:57 pan2.li
  2023-09-11  8:06 ` juzhe.zhong
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: pan2.li @ 2023-09-11  7:57 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, pan2.li, yanzhang.wang, kito.cheng

From: Pan Li <pan2.li@intel.com>

This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.

However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.

* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.

We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.

gcc/ChangeLog:

	* config/riscv/riscv-c.cc
	(riscv_resolve_overloaded_builtin): New function for the hook.
	(riscv_register_pragmas): Register the hook
	* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
	* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
	Register overloaded function.
	(struct overloaded_base): New struct for overloaded shape.
	(struct non_overloaded_base): New struct for non overloaded shape.
	(struct move_def): Inherit overloaded shape.
	* config/riscv/riscv-vector-builtins.cc
	(function_builder::add_function): Add overloaded arg.
	(function_builder::add_overloaded_function): New function impl.
	(function_resolver::function_resolver): New constructor.
	(function_resolver::get_sub_code): New API impl.
	(function_resolver::resolve): New API impl.
	(function_resolver::lookup): New API impl.
	(resolve_overloaded_builtin): New func impl.
	* config/riscv/riscv-vector-builtins.h
	(class function_resolver): New class.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
	* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
	* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv-c.cc                   |  36 +++++
 gcc/config/riscv/riscv-protos.h               |   1 +
 .../riscv/riscv-vector-builtins-shapes.cc     |  22 ++-
 gcc/config/riscv/riscv-vector-builtins.cc     | 138 +++++++++++++++++-
 gcc/config/riscv/riscv-vector-builtins.h      |  30 +++-
 .../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   4 +
 .../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   4 +
 .../riscv/rvv/base/overloaded_vmv_v.h         |  17 +++
 8 files changed, 248 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h

diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
 }
 
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+				  void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+							     arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+				  fndecl);
+}
+
 /* Implement REGISTER_TARGET_PRAGMAS.  */
 
 void
 riscv_register_pragmas (void)
 {
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
 }
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
 bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 bool legitimize_move (rtx, rtx);
 void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..6091016fa42 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
 			 argument_types);
 }
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
 };
 
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
 /* vsetvl_def class.  */
 struct vsetvl_def : public build_base
 {
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
 };
 
 /* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
 {
   char *get_name (function_builder &b, const function_instance &instance,
 		  bool overloaded_p) const override
@@ -545,7 +563,7 @@ struct move_def : public build_base
 
     /* According to rvv-intrinsic-doc, it does not add "_m" suffix
        for vop_m C++ overloaded API.  */
-    if (overloaded_p && instance.pred == PRED_TYPE_m)
+    if (overloaded_p)
       return b.finish_name ();
     b.append_name (predication_suffixes[instance.pred]);
     return b.finish_name ();
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..cc61e524dc7 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
 
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
 };
 
 /* Hash traits for registered_function.  */
@@ -3357,7 +3361,8 @@ function_builder::get_attributes (const function_instance &instance)
 registered_function &
 function_builder::add_function (const function_instance &instance,
 				const char *name, tree fntype, tree attrs,
-				bool placeholder_p)
+				bool placeholder_p,
+				bool overloaded_p = false)
 {
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3388,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
 
   return rfn;
@@ -3432,6 +3438,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
 }
 
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+					   const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, we use void return type and void argument
+	 for the overloaded function register, like aarch64-sve.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+		    true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
 function_call_info::function_call_info (location_t location_in,
 					const function_instance &instance_in,
 					tree fndecl_in)
@@ -3852,6 +3878,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
 {}
 
+function_resolver::function_resolver (location_t location,
+				      const function_instance &instance,
+				      tree fndecl,
+				      vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
 /* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
 void
@@ -3967,6 +4000,93 @@ function_checker::check ()
   return shape->check (*this);
 }
 
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+/* Perform the lookup from the registered functions.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL_TREE will be returned.
+ */
+tree
+function_resolver::lookup ()
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)
+    {
+      registered_function *rfun = (*registered_functions)[code];
+      function_instance instance = rfun->instance;
+
+      if (strcmp (base_name, instance.base_name) != 0)
+	break;
+
+      if (rfun->overloaded_p)
+	continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+	{
+	  if (k >= m_arglist.length ())
+	    break;
+
+	  if (TYPE_MODE (instance.get_arg_type (k))
+	    != TYPE_MODE (TREE_TYPE (m_arglist[k])))
+	    break;
+	}
+
+	if (args[k].base_type == NUM_BASE_TYPES)
+	  return rfun->decl;
+    }
+
+  return NULL_TREE;
+}
+
 inline hashval_t
 registered_function_hasher::hash (value_type value)
 {
@@ -4196,6 +4316,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
 			   TREE_TYPE (rfn.decl), nargs, args).check ();
 }
 
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+			    vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
 function_instance
 get_read_vl_instance (void)
 {
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..3a466a99770 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
 			    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+				const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
 
   registered_function &add_function (const function_instance &, const char *,
-				     tree, tree, bool);
+				     tree, tree, bool, bool);
 
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -462,6 +464,28 @@ private:
   tree *m_args;
 };
 
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+		     vec<tree, va_gc> &);
+
+  /* Lookup the non overloaded registered function decl
+     from the registered_functions table.  */
+  tree lookup ();
+
+  /* Resolve the overloaded function.  */
+  tree resolve ();
+
+private:
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
 /* Classifies functions into "shapes" base on:
 
    - Base name of the intrinsic function.
@@ -486,6 +510,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
 };
 
 extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..913fe678b51
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..52f65e9f8a8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..dd818320f63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,17 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11  7:57 [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic pan2.li
@ 2023-09-11  8:06 ` juzhe.zhong
  2023-09-11  9:04   ` Kito Cheng
  2023-09-12  7:20 ` [PATCH v2] " pan2.li
  2023-09-12  8:46 ` [PATCH v3] " pan2.li
  2 siblings, 1 reply; 22+ messages in thread
From: juzhe.zhong @ 2023-09-11  8:06 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: pan2.li, yanzhang.wang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 17883 bytes --]

Thanks for supporting it even though I don't like this feature :).
The framework is LGTM.

Let's wait for kito's more comments.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-09-11 15:57
To: gcc-patches
CC: juzhe.zhong; pan2.li; yanzhang.wang; kito.cheng
Subject: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com>
 
This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.
 
However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.
 
* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.
 
We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.
 
gcc/ChangeLog:
 
* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_builder::add_function): Add overloaded arg.
(function_builder::add_overloaded_function): New function impl.
(function_resolver::function_resolver): New constructor.
(function_resolver::get_sub_code): New API impl.
(function_resolver::resolve): New API impl.
(function_resolver::lookup): New API impl.
(resolve_overloaded_builtin): New func impl.
* config/riscv/riscv-vector-builtins.h
(class function_resolver): New class.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
---
gcc/config/riscv/riscv-c.cc                   |  36 +++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  22 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 138 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  30 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   4 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   4 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  17 +++
8 files changed, 248 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
 
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..6091016fa42 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
@@ -545,7 +563,7 @@ struct move_def : public build_base
     /* According to rvv-intrinsic-doc, it does not add "_m" suffix
        for vop_m C++ overloaded API.  */
-    if (overloaded_p && instance.pred == PRED_TYPE_m)
+    if (overloaded_p)
       return b.finish_name ();
     b.append_name (predication_suffixes[instance.pred]);
     return b.finish_name ();
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..cc61e524dc7 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3357,7 +3361,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3388,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3438,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, we use void return type and void argument
+ for the overloaded function register, like aarch64-sve.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3878,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4000,93 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+/* Perform the lookup from the registered functions.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL_TREE will be returned.
+ */
+tree
+function_resolver::lookup ()
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)
+    {
+      registered_function *rfun = (*registered_functions)[code];
+      function_instance instance = rfun->instance;
+
+      if (strcmp (base_name, instance.base_name) != 0)
+ break;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= m_arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (m_arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return rfun->decl;
+    }
+
+  return NULL_TREE;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4316,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..3a466a99770 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -462,6 +464,28 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Lookup the non overloaded registered function decl
+     from the registered_functions table.  */
+  tree lookup ();
+
+  /* Resolve the overloaded function.  */
+  tree resolve ();
+
+private:
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +510,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..913fe678b51
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..52f65e9f8a8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..dd818320f63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,17 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11  8:06 ` juzhe.zhong
@ 2023-09-11  9:04   ` Kito Cheng
  2023-09-11  9:13     ` juzhe.zhong
  0 siblings, 1 reply; 22+ messages in thread
From: Kito Cheng @ 2023-09-11  9:04 UTC (permalink / raw)
  To: juzhe.zhong; +Cc: pan2.li, gcc-patches, yanzhang.wang

> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Just make sure it's the right change?

>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11  9:04   ` Kito Cheng
@ 2023-09-11  9:13     ` juzhe.zhong
  2023-09-11 12:09       ` Li, Pan2
       [not found]       ` <03D4A8A613CD8015+D14577CD-36C5-493B-8B7E-1D83914B5C17@rivai.ai>
  0 siblings, 2 replies; 22+ messages in thread
From: juzhe.zhong @ 2023-09-11  9:13 UTC (permalink / raw)
  To: kito.cheng; +Cc: pan2.li, gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 2234 bytes --]

>> Just make sure it's the right change?
It seem incorrect to me.

More comments (I just reviewed again):

+tree
+function_resolver::lookup ()
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)
+    {
+      registered_function *rfun = (*registered_functions)[code];
+      function_instance instance = rfun->instance;
+
+      if (strcmp (base_name, instance.base_name) != 0)
+	break;
+
+      if (rfun->overloaded_p)
+	continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+	{
+	  if (k >= m_arglist.length ())
+	    break;
+
+	  if (TYPE_MODE (instance.get_arg_type (k))
+	    != TYPE_MODE (TREE_TYPE (m_arglist[k])))
+	    break;
+	}
+
+	if (args[k].base_type == NUM_BASE_TYPES)
+	  return rfun->decl;
+    }
+
+  return NULL_TREE;
+}
Plz change it into :
/* Silently check whether there is an instance of the function with the
   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.
   Return its function decl if so, otherwise return null.  */
tree
function_resolver::lookup_form (mode_suffix_index mode,
        type_suffix_index type0,
        type_suffix_index type1)
{
  type_suffix_pair types = { type0, type1 };
  function_instance instance (base_name, base, shape, mode, types, pred);
  registered_function *rfn
    = function_table->find_with_hash (instance, instance.hash ());
  return rfn ? rfn->decl : NULL_TREE;
}


juzhe.zhong@rivai.ai
 
From: Kito Cheng
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai
CC: pan2.li; gcc-patches; yanzhang.wang
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Just make sure it's the right change?
 
>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11  9:13     ` juzhe.zhong
@ 2023-09-11 12:09       ` Li, Pan2
       [not found]       ` <03D4A8A613CD8015+D14577CD-36C5-493B-8B7E-1D83914B5C17@rivai.ai>
  1 sibling, 0 replies; 22+ messages in thread
From: Li, Pan2 @ 2023-09-11 12:09 UTC (permalink / raw)
  To: juzhe.zhong, kito.cheng; +Cc: gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 3643 bytes --]

> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.


> Plz change it into :



Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.

Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.

Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are required

by function_instance when constructing.



Pan

From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com>
Cc: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

>> Just make sure it's the right change?
It seem incorrect to me.

More comments (I just reviewed again):


+tree

+function_resolver::lookup ()

+{

+  unsigned int code_limit = vec_safe_length (registered_functions);

+

+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)

+    {

+      registered_function *rfun = (*registered_functions)[code];

+      function_instance instance = rfun->instance;

+

+      if (strcmp (base_name, instance.base_name) != 0)

+       break;

+

+      if (rfun->overloaded_p)

+       continue;

+

+      unsigned k;

+      const rvv_arg_type_info *args = instance.op_info->args;

+

+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)

+       {

+         if (k >= m_arglist.length ())

+           break;

+

+         if (TYPE_MODE (instance.get_arg_type (k))

+           != TYPE_MODE (TREE_TYPE (m_arglist[k])))

+           break;

+       }

+

+       if (args[k].base_type == NUM_BASE_TYPES)

+         return rfun->decl;

+    }

+

+  return NULL_TREE;

+}



Plz change it into :



/* Silently check whether there is an instance of the function with the

   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.

   Return its function decl if so, otherwise return null.  */

tree

function_resolver::lookup_form (mode_suffix_index mode,

        type_suffix_index type0,

        type_suffix_index type1)

{

  type_suffix_pair types = { type0, type1 };

  function_instance instance (base_name, base, shape, mode, types, pred);

  registered_function *rfn

    = function_table->find_with_hash (instance, instance.hash ());

  return rfn ? rfn->decl : NULL_TREE;

}

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Kito Cheng<mailto:kito.cheng@gmail.com>
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>
CC: pan2.li<mailto:pan2.li@intel.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Just make sure it's the right change?

>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();


^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
       [not found]       ` <03D4A8A613CD8015+D14577CD-36C5-493B-8B7E-1D83914B5C17@rivai.ai>
@ 2023-09-11 12:26         ` Li, Pan2
  2023-09-11 13:06           ` 钟居哲
  0 siblings, 1 reply; 22+ messages in thread
From: Li, Pan2 @ 2023-09-11 12:26 UTC (permalink / raw)
  To: juzhe.zhong; +Cc: kito.cheng, gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 4919 bytes --]

> No. You must construct instance. 'strcmp' is very ugly.

Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.

Pan

From: juzhe.zhong <juzhe.zhong@rivai.ai>
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com><mailto:pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai><mailto:juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com><mailto:kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org><mailto:gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com><mailto:yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.


> Plz change it into :



Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.

Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.

Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are required

by function_instance when constructing.



Pan

From: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai> <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>
Cc: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

>> Just make sure it's the right change?
It seem incorrect to me.

More comments (I just reviewed again):


+tree

+function_resolver::lookup ()

+{

+  unsigned int code_limit = vec_safe_length (registered_functions);

+

+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)

+    {

+      registered_function *rfun = (*registered_functions)[code];

+      function_instance instance = rfun->instance;

+

+      if (strcmp (base_name, instance.base_name) != 0)

+       break;

+

+      if (rfun->overloaded_p)

+       continue;

+

+      unsigned k;

+      const rvv_arg_type_info *args = instance.op_info->args;

+

+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)

+       {

+         if (k >= m_arglist.length ())

+           break;

+

+         if (TYPE_MODE (instance.get_arg_type (k))

+           != TYPE_MODE (TREE_TYPE (m_arglist[k])))

+           break;

+       }

+

+       if (args[k].base_type == NUM_BASE_TYPES)

+         return rfun->decl;

+    }

+

+  return NULL_TREE;

+}



Plz change it into :



/* Silently check whether there is an instance of the function with the

   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.

   Return its function decl if so, otherwise return null.  */

tree

function_resolver::lookup_form (mode_suffix_index mode,

        type_suffix_index type0,

        type_suffix_index type1)

{

  type_suffix_pair types = { type0, type1 };

  function_instance instance (base_name, base, shape, mode, types, pred);

  registered_function *rfn

    = function_table->find_with_hash (instance, instance.hash ());

  return rfn ? rfn->decl : NULL_TREE;

}

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Kito Cheng<mailto:kito.cheng@gmail.com>
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>
CC: pan2.li<mailto:pan2.li@intel.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Just make sure it's the right change?

>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11 12:26         ` Li, Pan2
@ 2023-09-11 13:06           ` 钟居哲
  2023-09-11 15:24             ` Li, Pan2
  0 siblings, 1 reply; 22+ messages in thread
From: 钟居哲 @ 2023-09-11 13:06 UTC (permalink / raw)
  To: pan2.li; +Cc: kito.cheng, gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 4993 bytes --]

function_instance
get_read_vl_instance (void)
{
  return function_instance ("read_vl", bases::read_vl, shapes::read_vl,
          none_ops[0], PRED_TYPE_none, &p_none_void_ops);
}

tree
get_read_vl_decl (void)
{
  function_instance instance = get_read_vl_instance ();
  hashval_t hash = instance.hash ();
  registered_function *rfn = function_table->find_with_hash (instance, hash);
  gcc_assert (rfn);
  return rfn->decl;
}

You should reference it. I don't see why it's hard for use to construct instance first, then use that instance hash to get the decl.


juzhe.zhong@rivai.ai
 
From: Li, Pan2
Date: 2023-09-11 20:26
To: juzhe.zhong
CC: kito.cheng; gcc-patches; Wang, Yanzhang
Subject: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> No. You must construct instance. 'strcmp' is very ugly.
 
Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.
 
Pan
 
From: juzhe.zhong <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.
 
> Plz change it into : Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are requiredby function_instance when constructing. Pan
 
From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com>
Cc: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
>> Just make sure it's the right change?
It seem incorrect to me.
 
More comments (I just reviewed again):
 
+tree+function_resolver::lookup ()+{+  unsigned int code_limit = vec_safe_length (registered_functions);++  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)+    {+      registered_function *rfun = (*registered_functions)[code];+      function_instance instance = rfun->instance;++      if (strcmp (base_name, instance.base_name) != 0)+       break;++      if (rfun->overloaded_p)+       continue;++      unsigned k;+      const rvv_arg_type_info *args = instance.op_info->args;++      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)+       {+         if (k >= m_arglist.length ())+           break;++         if (TYPE_MODE (instance.get_arg_type (k))+           != TYPE_MODE (TREE_TYPE (m_arglist[k])))+           break;+       }++       if (args[k].base_type == NUM_BASE_TYPES)+         return rfun->decl;+    }++  return NULL_TREE;+} Plz change it into : 
/* Silently check whether there is an instance of the function with the
   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.
   Return its function decl if so, otherwise return null.  */
tree
function_resolver::lookup_form (mode_suffix_index mode,
        type_suffix_index type0,
        type_suffix_index type1)
{
  type_suffix_pair types = { type0, type1 };
  function_instance instance (base_name, base, shape, mode, types, pred);
  registered_function *rfn
    = function_table->find_with_hash (instance, instance.hash ());
  return rfn ? rfn->decl : NULL_TREE;
}


juzhe.zhong@rivai.ai
 
From: Kito Cheng
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai
CC: pan2.li; gcc-patches; yanzhang.wang
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Just make sure it's the right change?
 
>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11 13:06           ` 钟居哲
@ 2023-09-11 15:24             ` Li, Pan2
  2023-09-11 23:19               ` 钟居哲
  0 siblings, 1 reply; 22+ messages in thread
From: Li, Pan2 @ 2023-09-11 15:24 UTC (permalink / raw)
  To: 钟居哲; +Cc: kito.cheng, gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 6936 bytes --]

For function instance with void or void arguments, it is easy as you mentioned as below.

For generate API (to get the right hash), you need to build the rvv_type_info, predications_type_index and rvv_op_info
from the arglist (aka vec<tree, va_gc>) from hook.

Then we need to construct above parameters from one tree argument. Sorry I not sure if I understand correctly but I failed
to locate somewhere has similar usage.

Could you please help to insight me some best practice about the transformation from tree to above types?

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai>
Sent: Monday, September 11, 2023 9:07 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

function_instance
get_read_vl_instance (void)
{
  return function_instance ("read_vl", bases::read_vl, shapes::read_vl,
          none_ops[0], PRED_TYPE_none, &p_none_void_ops);
}

tree
get_read_vl_decl (void)
{
  function_instance instance = get_read_vl_instance ();
  hashval_t hash = instance.hash ();
  registered_function *rfn = function_table->find_with_hash (instance, hash);
  gcc_assert (rfn);
  return rfn->decl;
}

You should reference it. I don't see why it's hard for use to construct instance first, then use that instance hash to get the decl.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Li, Pan2<mailto:pan2.li@intel.com>
Date: 2023-09-11 20:26
To: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>
CC: kito.cheng<mailto:kito.cheng@gmail.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> No. You must construct instance. 'strcmp' is very ugly.

Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.

Pan

From: juzhe.zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com><mailto:pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai><mailto:juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com><mailto:kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org><mailto:gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com><mailto:yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.


> Plz change it into :



Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.

Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.

Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are required

by function_instance when constructing.



Pan

From: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai> <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>
Cc: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

>> Just make sure it's the right change?
It seem incorrect to me.

More comments (I just reviewed again):


+tree

+function_resolver::lookup ()

+{

+  unsigned int code_limit = vec_safe_length (registered_functions);

+

+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)

+    {

+      registered_function *rfun = (*registered_functions)[code];

+      function_instance instance = rfun->instance;

+

+      if (strcmp (base_name, instance.base_name) != 0)

+      break;

+

+      if (rfun->overloaded_p)

+      continue;

+

+      unsigned k;

+      const rvv_arg_type_info *args = instance.op_info->args;

+

+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)

+      {

+        if (k >= m_arglist.length ())

+          break;

+

+        if (TYPE_MODE (instance.get_arg_type (k))

+          != TYPE_MODE (TREE_TYPE (m_arglist[k])))

+          break;

+      }

+

+      if (args[k].base_type == NUM_BASE_TYPES)

+        return rfun->decl;

+    }

+

+  return NULL_TREE;

+}



Plz change it into :



/* Silently check whether there is an instance of the function with the

   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.

   Return its function decl if so, otherwise return null.  */

tree

function_resolver::lookup_form (mode_suffix_index mode,

        type_suffix_index type0,

        type_suffix_index type1)

{

  type_suffix_pair types = { type0, type1 };

  function_instance instance (base_name, base, shape, mode, types, pred);

  registered_function *rfn

    = function_table->find_with_hash (instance, instance.hash ());

  return rfn ? rfn->decl : NULL_TREE;

}

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Kito Cheng<mailto:kito.cheng@gmail.com>
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>
CC: pan2.li<mailto:pan2.li@intel.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Just make sure it's the right change?

>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11 15:24             ` Li, Pan2
@ 2023-09-11 23:19               ` 钟居哲
  2023-09-12  1:20                 ` Li, Pan2
  0 siblings, 1 reply; 22+ messages in thread
From: 钟居哲 @ 2023-09-11 23:19 UTC (permalink / raw)
  To: pan2.li; +Cc: kito.cheng, gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 6607 bytes --]

I don't understand.

+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+			    vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
You already have rfun->instance. Just use this instance should be good enough.


juzhe.zhong@rivai.ai
 
From: Li, Pan2
Date: 2023-09-11 23:24
To: 钟居哲
CC: kito.cheng; gcc-patches; Wang, Yanzhang
Subject: RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
For function instance with void or void arguments, it is easy as you mentioned as below.
 
For generate API (to get the right hash), you need to build the rvv_type_info, predications_type_index and rvv_op_info
from the arglist (aka vec<tree, va_gc>) from hook.
 
Then we need to construct above parameters from one tree argument. Sorry I not sure if I understand correctly but I failed
to locate somewhere has similar usage.
 
Could you please help to insight me some best practice about the transformation from tree to above types?
 
Pan
 
From: 钟居哲 <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 9:07 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
function_instance
get_read_vl_instance (void)
{
  return function_instance ("read_vl", bases::read_vl, shapes::read_vl,
          none_ops[0], PRED_TYPE_none, &p_none_void_ops);
}
 
tree
get_read_vl_decl (void)
{
  function_instance instance = get_read_vl_instance ();
  hashval_t hash = instance.hash ();
  registered_function *rfn = function_table->find_with_hash (instance, hash);
  gcc_assert (rfn);
  return rfn->decl;
}
 
You should reference it. I don't see why it's hard for use to construct instance first, then use that instance hash to get the decl.


juzhe.zhong@rivai.ai
 
From: Li, Pan2
Date: 2023-09-11 20:26
To: juzhe.zhong
CC: kito.cheng; gcc-patches; Wang, Yanzhang
Subject: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> No. You must construct instance. 'strcmp' is very ugly.
 
Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.
 
Pan
 
From: juzhe.zhong <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.
 
> Plz change it into : Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are requiredby function_instance when constructing. Pan
 
From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com>
Cc: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
>> Just make sure it's the right change?
It seem incorrect to me.
 
More comments (I just reviewed again):
 
+tree+function_resolver::lookup ()+{+  unsigned int code_limit = vec_safe_length (registered_functions);++  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)+    {+      registered_function *rfun = (*registered_functions)[code];+      function_instance instance = rfun->instance;++      if (strcmp (base_name, instance.base_name) != 0)+      break;++      if (rfun->overloaded_p)+      continue;++      unsigned k;+      const rvv_arg_type_info *args = instance.op_info->args;++      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)+      {+        if (k >= m_arglist.length ())+          break;++        if (TYPE_MODE (instance.get_arg_type (k))+          != TYPE_MODE (TREE_TYPE (m_arglist[k])))+          break;+      }++      if (args[k].base_type == NUM_BASE_TYPES)+        return rfun->decl;+    }++  return NULL_TREE;+} Plz change it into : 
/* Silently check whether there is an instance of the function with the
   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.
   Return its function decl if so, otherwise return null.  */
tree
function_resolver::lookup_form (mode_suffix_index mode,
        type_suffix_index type0,
        type_suffix_index type1)
{
  type_suffix_pair types = { type0, type1 };
  function_instance instance (base_name, base, shape, mode, types, pred);
  registered_function *rfn
    = function_table->find_with_hash (instance, instance.hash ());
  return rfn ? rfn->decl : NULL_TREE;
}


juzhe.zhong@rivai.ai
 
From: Kito Cheng
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai
CC: pan2.li; gcc-patches; yanzhang.wang
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Just make sure it's the right change?
 
>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11 23:19               ` 钟居哲
@ 2023-09-12  1:20                 ` Li, Pan2
  2023-09-12  1:29                   ` juzhe.zhong
  0 siblings, 1 reply; 22+ messages in thread
From: Li, Pan2 @ 2023-09-12  1:20 UTC (permalink / raw)
  To: 钟居哲; +Cc: kito.cheng, gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 9320 bytes --]

We cannot leverage this instance for correctness.
The rfun of below code is the overloaded builtin is for the overloaded function, which is registered as void xxx(void) as aarch64 did to avoid the conflict.

Let’s take vmv_v_i32m1 as example in rfun table.

Index 0: void vmv_v(void) overloaded
Index 1: i32m1 vmv_v_v_i32m1_i32m1 (i32m1, size_t) non-overloaded
Index 2: placeholder.

When we enter the hook(aka the code list below), the rfun we have is the index 0 rfun instead of index 1.
Then we need the arglist to lookup the rfun of index 1 for the underlying call, as well as build the instance for the index 1 rfun.

Aarch64 has the same rfun table as above, they leverage a loop to parse the arglist with machine mode matching in a predefined type suffix(which is not available in RISC-V).

I think they almost try to resolve the same problem but different implement details.

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai>
Sent: Tuesday, September 12, 2023 7:20 AM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

I don't understand.


+tree

+resolve_overloaded_builtin (location_t loc, unsigned int code,

+                          vec<tree, va_gc> *arglist)

+{

+  if (code >= vec_safe_length (registered_functions))

+    return NULL_TREE;

+

+  const registered_function *rfun = (*registered_functions)[code];

+

+  if (!rfun || !rfun->overloaded_p)

+    return NULL_TREE;

+

+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)

+    .resolve ();

+}
You already have rfun->instance. Just use this instance should be good enough.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Li, Pan2<mailto:pan2.li@intel.com>
Date: 2023-09-11 23:24
To: 钟居哲<mailto:juzhe.zhong@rivai.ai>
CC: kito.cheng<mailto:kito.cheng@gmail.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
For function instance with void or void arguments, it is easy as you mentioned as below.

For generate API (to get the right hash), you need to build the rvv_type_info, predications_type_index and rvv_op_info
from the arglist (aka vec<tree, va_gc>) from hook.

Then we need to construct above parameters from one tree argument. Sorry I not sure if I understand correctly but I failed
to locate somewhere has similar usage.

Could you please help to insight me some best practice about the transformation from tree to above types?

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 9:07 PM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

function_instance
get_read_vl_instance (void)
{
  return function_instance ("read_vl", bases::read_vl, shapes::read_vl,
          none_ops[0], PRED_TYPE_none, &p_none_void_ops);
}

tree
get_read_vl_decl (void)
{
  function_instance instance = get_read_vl_instance ();
  hashval_t hash = instance.hash ();
  registered_function *rfn = function_table->find_with_hash (instance, hash);
  gcc_assert (rfn);
  return rfn->decl;
}

You should reference it. I don't see why it's hard for use to construct instance first, then use that instance hash to get the decl.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Li, Pan2<mailto:pan2.li@intel.com>
Date: 2023-09-11 20:26
To: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>
CC: kito.cheng<mailto:kito.cheng@gmail.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> No. You must construct instance. 'strcmp' is very ugly.

Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.

Pan

From: juzhe.zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com><mailto:pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai><mailto:juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com><mailto:kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org><mailto:gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com><mailto:yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.


> Plz change it into :



Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.

Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.

Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are required

by function_instance when constructing.



Pan

From: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai> <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>
Cc: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

>> Just make sure it's the right change?
It seem incorrect to me.

More comments (I just reviewed again):


+tree

+function_resolver::lookup ()

+{

+  unsigned int code_limit = vec_safe_length (registered_functions);

+

+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)

+    {

+      registered_function *rfun = (*registered_functions)[code];

+      function_instance instance = rfun->instance;

+

+      if (strcmp (base_name, instance.base_name) != 0)

+     break;

+

+      if (rfun->overloaded_p)

+     continue;

+

+      unsigned k;

+      const rvv_arg_type_info *args = instance.op_info->args;

+

+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)

+     {

+       if (k >= m_arglist.length ())

+         break;

+

+       if (TYPE_MODE (instance.get_arg_type (k))

+         != TYPE_MODE (TREE_TYPE (m_arglist[k])))

+         break;

+     }

+

+     if (args[k].base_type == NUM_BASE_TYPES)

+       return rfun->decl;

+    }

+

+  return NULL_TREE;

+}



Plz change it into :



/* Silently check whether there is an instance of the function with the

   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.

   Return its function decl if so, otherwise return null.  */

tree

function_resolver::lookup_form (mode_suffix_index mode,

        type_suffix_index type0,

        type_suffix_index type1)

{

  type_suffix_pair types = { type0, type1 };

  function_instance instance (base_name, base, shape, mode, types, pred);

  registered_function *rfn

    = function_table->find_with_hash (instance, instance.hash ());

  return rfn ? rfn->decl : NULL_TREE;

}

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Kito Cheng<mailto:kito.cheng@gmail.com>
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>
CC: pan2.li<mailto:pan2.li@intel.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Just make sure it's the right change?

>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  1:20                 ` Li, Pan2
@ 2023-09-12  1:29                   ` juzhe.zhong
  2023-09-12  1:50                     ` Li, Pan2
  0 siblings, 1 reply; 22+ messages in thread
From: juzhe.zhong @ 2023-09-12  1:29 UTC (permalink / raw)
  To: pan2.li; +Cc: kito.cheng, gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 8267 bytes --]

Add a function call get_non_overloaded_instance into instance.
The instance already know it is void vmv (void).
In this function search the arglist. and return the real non-overloaded decl.



juzhe.zhong@rivai.ai
 
From: Li, Pan2
Date: 2023-09-12 09:20
To: 钟居哲
CC: kito.cheng; gcc-patches; Wang, Yanzhang
Subject: RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
We cannot leverage this instance for correctness.
The rfun of below code is the overloaded builtin is for the overloaded function, which is registered as void xxx(void) as aarch64 did to avoid the conflict.
 
Let’s take vmv_v_i32m1 as example in rfun table.
 
Index 0: void vmv_v(void) overloaded
Index 1: i32m1 vmv_v_v_i32m1_i32m1 (i32m1, size_t) non-overloaded
Index 2: placeholder.
 
When we enter the hook(aka the code list below), the rfun we have is the index 0 rfun instead of index 1.
Then we need the arglist to lookup the rfun of index 1 for the underlying call, as well as build the instance for the index 1 rfun.
 
Aarch64 has the same rfun table as above, they leverage a loop to parse the arglist with machine mode matching in a predefined type suffix(which is not available in RISC-V).
 
I think they almost try to resolve the same problem but different implement details.
 
Pan
 
From: 钟居哲 <juzhe.zhong@rivai.ai> 
Sent: Tuesday, September 12, 2023 7:20 AM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
I don't understand.
 
+tree+resolve_overloaded_builtin (location_t loc, unsigned int code,+                          vec<tree, va_gc> *arglist)+{+  if (code >= vec_safe_length (registered_functions))+    return NULL_TREE;++  const registered_function *rfun = (*registered_functions)[code];++  if (!rfun || !rfun->overloaded_p)+    return NULL_TREE;++  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)+    .resolve ();+}
You already have rfun->instance. Just use this instance should be good enough.


juzhe.zhong@rivai.ai
 
From: Li, Pan2
Date: 2023-09-11 23:24
To: 钟居哲
CC: kito.cheng; gcc-patches; Wang, Yanzhang
Subject: RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
For function instance with void or void arguments, it is easy as you mentioned as below.
 
For generate API (to get the right hash), you need to build the rvv_type_info, predications_type_index and rvv_op_info
from the arglist (aka vec<tree, va_gc>) from hook.
 
Then we need to construct above parameters from one tree argument. Sorry I not sure if I understand correctly but I failed
to locate somewhere has similar usage.
 
Could you please help to insight me some best practice about the transformation from tree to above types?
 
Pan
 
From: 钟居哲 <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 9:07 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
function_instance
get_read_vl_instance (void)
{
  return function_instance ("read_vl", bases::read_vl, shapes::read_vl,
          none_ops[0], PRED_TYPE_none, &p_none_void_ops);
}
 
tree
get_read_vl_decl (void)
{
  function_instance instance = get_read_vl_instance ();
  hashval_t hash = instance.hash ();
  registered_function *rfn = function_table->find_with_hash (instance, hash);
  gcc_assert (rfn);
  return rfn->decl;
}
 
You should reference it. I don't see why it's hard for use to construct instance first, then use that instance hash to get the decl.


juzhe.zhong@rivai.ai
 
From: Li, Pan2
Date: 2023-09-11 20:26
To: juzhe.zhong
CC: kito.cheng; gcc-patches; Wang, Yanzhang
Subject: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> No. You must construct instance. 'strcmp' is very ugly.
 
Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.
 
Pan
 
From: juzhe.zhong <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.
 
> Plz change it into : Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are requiredby function_instance when constructing. Pan
 
From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai> 
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com>
Cc: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
 
>> Just make sure it's the right change?
It seem incorrect to me.
 
More comments (I just reviewed again):
 
+tree+function_resolver::lookup ()+{+  unsigned int code_limit = vec_safe_length (registered_functions);++  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)+    {+      registered_function *rfun = (*registered_functions)[code];+      function_instance instance = rfun->instance;++      if (strcmp (base_name, instance.base_name) != 0)+     break;++      if (rfun->overloaded_p)+     continue;++      unsigned k;+      const rvv_arg_type_info *args = instance.op_info->args;++      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)+     {+       if (k >= m_arglist.length ())+         break;++       if (TYPE_MODE (instance.get_arg_type (k))+         != TYPE_MODE (TREE_TYPE (m_arglist[k])))+         break;+     }++     if (args[k].base_type == NUM_BASE_TYPES)+       return rfun->decl;+    }++  return NULL_TREE;+} Plz change it into : 
/* Silently check whether there is an instance of the function with the
   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.
   Return its function decl if so, otherwise return null.  */
tree
function_resolver::lookup_form (mode_suffix_index mode,
        type_suffix_index type0,
        type_suffix_index type1)
{
  type_suffix_pair types = { type0, type1 };
  function_instance instance (base_name, base, shape, mode, types, pred);
  registered_function *rfn
    = function_table->find_with_hash (instance, instance.hash ());
  return rfn ? rfn->decl : NULL_TREE;
}


juzhe.zhong@rivai.ai
 
From: Kito Cheng
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai
CC: pan2.li; gcc-patches; yanzhang.wang
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)
 
Just make sure it's the right change?
 
>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  1:29                   ` juzhe.zhong
@ 2023-09-12  1:50                     ` Li, Pan2
  0 siblings, 0 replies; 22+ messages in thread
From: Li, Pan2 @ 2023-09-12  1:50 UTC (permalink / raw)
  To: juzhe.zhong; +Cc: kito.cheng, gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 10455 bytes --]

Got it, will have a try.

Pan

From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Tuesday, September 12, 2023 9:30 AM
To: Li, Pan2 <pan2.li@intel.com>
Cc: kito.cheng <kito.cheng@gmail.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

Add a function call get_non_overloaded_instance into instance.
The instance already know it is void vmv (void).
In this function search the arglist. and return the real non-overloaded decl.

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Li, Pan2<mailto:pan2.li@intel.com>
Date: 2023-09-12 09:20
To: 钟居哲<mailto:juzhe.zhong@rivai.ai>
CC: kito.cheng<mailto:kito.cheng@gmail.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
We cannot leverage this instance for correctness.
The rfun of below code is the overloaded builtin is for the overloaded function, which is registered as void xxx(void) as aarch64 did to avoid the conflict.

Let’s take vmv_v_i32m1 as example in rfun table.

Index 0: void vmv_v(void) overloaded
Index 1: i32m1 vmv_v_v_i32m1_i32m1 (i32m1, size_t) non-overloaded
Index 2: placeholder.

When we enter the hook(aka the code list below), the rfun we have is the index 0 rfun instead of index 1.
Then we need the arglist to lookup the rfun of index 1 for the underlying call, as well as build the instance for the index 1 rfun.

Aarch64 has the same rfun table as above, they leverage a loop to parse the arglist with machine mode matching in a predefined type suffix(which is not available in RISC-V).

I think they almost try to resolve the same problem but different implement details.

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Tuesday, September 12, 2023 7:20 AM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

I don't understand.


+tree

+resolve_overloaded_builtin (location_t loc, unsigned int code,

+                         vec<tree, va_gc> *arglist)

+{

+  if (code >= vec_safe_length (registered_functions))

+    return NULL_TREE;

+

+  const registered_function *rfun = (*registered_functions)[code];

+

+  if (!rfun || !rfun->overloaded_p)

+    return NULL_TREE;

+

+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)

+    .resolve ();

+}
You already have rfun->instance. Just use this instance should be good enough.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Li, Pan2<mailto:pan2.li@intel.com>
Date: 2023-09-11 23:24
To: 钟居哲<mailto:juzhe.zhong@rivai.ai>
CC: kito.cheng<mailto:kito.cheng@gmail.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: RE: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
For function instance with void or void arguments, it is easy as you mentioned as below.

For generate API (to get the right hash), you need to build the rvv_type_info, predications_type_index and rvv_op_info
from the arglist (aka vec<tree, va_gc>) from hook.

Then we need to construct above parameters from one tree argument. Sorry I not sure if I understand correctly but I failed
to locate somewhere has similar usage.

Could you please help to insight me some best practice about the transformation from tree to above types?

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 9:07 PM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

function_instance
get_read_vl_instance (void)
{
  return function_instance ("read_vl", bases::read_vl, shapes::read_vl,
          none_ops[0], PRED_TYPE_none, &p_none_void_ops);
}

tree
get_read_vl_decl (void)
{
  function_instance instance = get_read_vl_instance ();
  hashval_t hash = instance.hash ();
  registered_function *rfn = function_table->find_with_hash (instance, hash);
  gcc_assert (rfn);
  return rfn->decl;
}

You should reference it. I don't see why it's hard for use to construct instance first, then use that instance hash to get the decl.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Li, Pan2<mailto:pan2.li@intel.com>
Date: 2023-09-11 20:26
To: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>
CC: kito.cheng<mailto:kito.cheng@gmail.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: RE: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> No. You must construct instance. 'strcmp' is very ugly.

Strcmp here is defensive code here for early exit if not found (can be removed for correctness), which is not required to find the right declaration.

Pan

From: juzhe.zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 8:20 PM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

No. You must construct instance. 'strcmp' is very ugly.
---- Replied Message ----
From
Li, Pan2<pan2.li@intel.com><mailto:pan2.li@intel.com>
Date
09/11/2023 20:09
To
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai><mailto:juzhe.zhong@rivai.ai>,
kito.cheng<kito.cheng@gmail.com><mailto:kito.cheng@gmail.com>
Cc
gcc-patches<gcc-patches@gcc.gnu.org><mailto:gcc-patches@gcc.gnu.org>,
Wang, Yanzhang<yanzhang.wang@intel.com><mailto:yanzhang.wang@intel.com>
Subject
RE: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Thanks for pointing this out, my misunderstanding for policy function result in this change as mistake, will send V2 for this.


> Plz change it into :



Actually, it is not easy to convert to this approach as aarch64 has different implementation of types information.

Like type_suffix_info (aarch64 loop type suffix to get the arglist type in infer_vector_or_tuple_type) etc.

Thus, it is not easy to construct rvv_type_info, predication_type_index and rvv_op_info from arglist, these are required

by function_instance when constructing.



Pan

From: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai> <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, September 11, 2023 5:13 PM
To: kito.cheng <kito.cheng@gmail.com<mailto:kito.cheng@gmail.com>>
Cc: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

>> Just make sure it's the right change?
It seem incorrect to me.

More comments (I just reviewed again):


+tree

+function_resolver::lookup ()

+{

+  unsigned int code_limit = vec_safe_length (registered_functions);

+

+  for (unsigned code = get_sub_code () + 1; code < code_limit; code++)

+    {

+      registered_function *rfun = (*registered_functions)[code];

+      function_instance instance = rfun->instance;

+

+      if (strcmp (base_name, instance.base_name) != 0)

+    break;

+

+      if (rfun->overloaded_p)

+    continue;

+

+      unsigned k;

+      const rvv_arg_type_info *args = instance.op_info->args;

+

+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)

+    {

+      if (k >= m_arglist.length ())

+        break;

+

+      if (TYPE_MODE (instance.get_arg_type (k))

+        != TYPE_MODE (TREE_TYPE (m_arglist[k])))

+        break;

+    }

+

+    if (args[k].base_type == NUM_BASE_TYPES)

+      return rfun->decl;

+    }

+

+  return NULL_TREE;

+}



Plz change it into :



/* Silently check whether there is an instance of the function with the

   mode suffix given by MODE and the type suffixes given by TYPE0 and TYPE1.

   Return its function decl if so, otherwise return null.  */

tree

function_resolver::lookup_form (mode_suffix_index mode,

        type_suffix_index type0,

        type_suffix_index type1)

{

  type_suffix_pair types = { type0, type1 };

  function_instance instance (base_name, base, shape, mode, types, pred);

  registered_function *rfn

    = function_table->find_with_hash (instance, instance.hash ());

  return rfn ? rfn->decl : NULL_TREE;

}

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Kito Cheng<mailto:kito.cheng@gmail.com>
Date: 2023-09-11 17:04
To: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>
CC: pan2.li<mailto:pan2.li@intel.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
> @@ -545,7 +563,7 @@ struct move_def : public build_base
>      /* According to rvv-intrinsic-doc, it does not add "_m" suffix
>         for vop_m C++ overloaded API.  */
> -    if (overloaded_p && instance.pred == PRED_TYPE_m)
> +    if (overloaded_p)

Just make sure it's the right change?

>        return b.finish_name ();
>      b.append_name (predication_suffixes[instance.pred]);
>      return b.finish_name ();


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11  7:57 [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic pan2.li
  2023-09-11  8:06 ` juzhe.zhong
@ 2023-09-12  7:20 ` pan2.li
  2023-09-12  7:46   ` juzhe.zhong
  2023-09-12  8:46 ` [PATCH v3] " pan2.li
  2 siblings, 1 reply; 22+ messages in thread
From: pan2.li @ 2023-09-12  7:20 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, pan2.li, yanzhang.wang, kito.cheng

From: Pan Li <pan2.li@intel.com>

Update in v2:

* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.

Original log:

This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.

However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.

* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.

We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.

gcc/ChangeLog:

	* config/riscv/riscv-c.cc
	(riscv_resolve_overloaded_builtin): New function for the hook.
	(riscv_register_pragmas): Register the hook
	* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
	* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
	Register overloaded function.
	(struct overloaded_base): New struct for overloaded shape.
	(struct non_overloaded_base): New struct for non overloaded shape.
	(struct move_def): Inherit overloaded shape.
	* config/riscv/riscv-vector-builtins.cc
	(function_instance::get_non_overloaded_instance): New API impl.
	(function_builder::add_function): Add overloaded arg.
	(function_resolver::function_resolver): New constructor.
	(function_builder::add_overloaded_function): New API impl.
	(function_resolver::resolve): Ditto.
	(function_resolver::lookup): Ditto.
	(function_resolver::get_sub_code): Ditto.
	(resolve_overloaded_builtin): New function impl.
	* config/riscv/riscv-vector-builtins.h:
	(class function_resolver): New class.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
	* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
	* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv-c.cc                   |  36 ++++
 gcc/config/riscv/riscv-protos.h               |   1 +
 .../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
 gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
 gcc/config/riscv/riscv-vector-builtins.h      |  35 +++-
 .../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
 .../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
 .../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
 8 files changed, 287 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h

diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
 }
 
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+				  void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+							     arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+				  fndecl);
+}
+
 /* Implement REGISTER_TARGET_PRAGMAS.  */
 
 void
 riscv_register_pragmas (void)
 {
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
 }
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
 bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 bool legitimize_move (rtx, rtx);
 void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
 			 argument_types);
 }
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
 };
 
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
 /* vsetvl_def class.  */
 struct vsetvl_def : public build_base
 {
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
 };
 
 /* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
 {
   char *get_name (function_builder &b, const function_instance &instance,
 		  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..41ecbb48461 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
 
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
 };
 
 /* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
 }
 
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_instance::get_non_overloaded_instance (unsigned int code,
+						vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+	continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+	{
+	  if (k >= arglist.length ())
+	    break;
+
+	  if (TYPE_MODE (instance.get_arg_type (k))
+	    != TYPE_MODE (TREE_TYPE (arglist[k])))
+	    break;
+	}
+
+	if (args[k].base_type == NUM_BASE_TYPES)
+	  return &rfun->instance;
+    }
+
+  return NULL;
+}
+
 function_builder::function_builder ()
 {
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
 registered_function &
 function_builder::add_function (const function_instance &instance,
 				const char *name, tree fntype, tree attrs,
-				bool placeholder_p)
+				bool placeholder_p,
+				bool overloaded_p = false)
 {
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
 
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
 }
 
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+					   const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, we use void return type and void argument
+	 for the overloaded function register, like aarch64-sve.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+		    true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
 function_call_info::function_call_info (location_t location_in,
 					const function_instance &instance_in,
 					tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
 {}
 
+function_resolver::function_resolver (location_t location,
+				      const function_instance &instance,
+				      tree fndecl,
+				      vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
 /* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
 void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
 }
 
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance = get_non_overloaded_instance (fun_code,
+							     m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
 inline hashval_t
 registered_function_hasher::hash (value_type value)
 {
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
 			   TREE_TYPE (rfn.decl), nargs, args).check ();
 }
 
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+			    vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
 function_instance
 get_read_vl_instance (void)
 {
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..5f8f7a97315 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -256,6 +256,10 @@ public:
   tree get_return_type () const;
   tree get_arg_type (unsigned opno) const;
 
+  function_instance * get_non_overloaded_instance (unsigned int,
+						   vec<tree, va_gc> &arglist)
+						   const;
+
   /* The properties of the function.  (The explicit "enum"s are required
      for gengtype.)  */
   const char *base_name;
@@ -277,6 +281,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
 			    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+				const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +294,7 @@ private:
   tree get_attributes (const function_instance &);
 
   registered_function &add_function (const function_instance &, const char *,
-				     tree, tree, bool);
+				     tree, tree, bool, bool);
 
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -462,6 +468,29 @@ private:
   tree *m_args;
 };
 
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+		     vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
 /* Classifies functions into "shapes" base on:
 
    - Base name of the intrinsic function.
@@ -486,6 +515,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
 };
 
 extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+				 size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+				     size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  7:20 ` [PATCH v2] " pan2.li
@ 2023-09-12  7:46   ` juzhe.zhong
  2023-09-12  7:53     ` Li, Pan2
  0 siblings, 1 reply; 22+ messages in thread
From: juzhe.zhong @ 2023-09-12  7:46 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: pan2.li, yanzhang.wang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 19957 bytes --]

I think it's better to move 'get_non_overloaded_instance' into function_base.

+      /* To avoid API conflicting, we use void return type and void argument
+ for the overloaded function register, like aarch64-sve.  */

Plz rewrite the comments, don't mention aarch64 sve.

Could you run your rvv intrinsic api ci with this patch?
I am worrying that the resolve stuff will destroy the existing APi support.




juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-09-12 15:20
To: gcc-patches
CC: juzhe.zhong; pan2.li; yanzhang.wang; kito.cheng
Subject: [PATCH v2] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com>
 
Update in v2:
 
* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.
 
Original log:
 
This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.
 
However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.
 
* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.
 
We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.
 
gcc/ChangeLog:
 
* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_instance::get_non_overloaded_instance): New API impl.
(function_builder::add_function): Add overloaded arg.
(function_resolver::function_resolver): New constructor.
(function_builder::add_overloaded_function): New API impl.
(function_resolver::resolve): Ditto.
(function_resolver::lookup): Ditto.
(function_resolver::get_sub_code): Ditto.
(resolve_overloaded_builtin): New function impl.
* config/riscv/riscv-vector-builtins.h:
(class function_resolver): New class.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
---
gcc/config/riscv/riscv-c.cc                   |  36 ++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  35 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
8 files changed, 287 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
 
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..41ecbb48461 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
}
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_instance::get_non_overloaded_instance (unsigned int code,
+ vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}
+
function_builder::function_builder ()
{
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, we use void return type and void argument
+ for the overloaded function register, like aarch64-sve.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance = get_non_overloaded_instance (fun_code,
+      m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..5f8f7a97315 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -256,6 +256,10 @@ public:
   tree get_return_type () const;
   tree get_arg_type (unsigned opno) const;
+  function_instance * get_non_overloaded_instance (unsigned int,
+    vec<tree, va_gc> &arglist)
+    const;
+
   /* The properties of the function.  (The explicit "enum"s are required
      for gengtype.)  */
   const char *base_name;
@@ -277,6 +281,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +294,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -462,6 +468,29 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +515,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+ size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+      size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH v2] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  7:46   ` juzhe.zhong
@ 2023-09-12  7:53     ` Li, Pan2
  0 siblings, 0 replies; 22+ messages in thread
From: Li, Pan2 @ 2023-09-12  7:53 UTC (permalink / raw)
  To: juzhe.zhong, gcc-patches; +Cc: Wang, Yanzhang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 21073 bytes --]

>I think it's better to move 'get_non_overloaded_instance' into function_base.
Sure.
> Plz rewrite the comments, don't mention aarch64 sve.
Sure

>Could you run your rvv intrinsic api ci with this patch?
>I am worrying that the resolve stuff will destroy the existing APi support.

This patch only enable the resolving for vmv_v, the test cases ensure the correctness for
both the exiting API and overloaded API of vmv_v.

Will send the v3 for this change.

Pan


From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Tuesday, September 12, 2023 3:47 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Li, Pan2 <pan2.li@intel.com>; Wang, Yanzhang <yanzhang.wang@intel.com>; kito.cheng <kito.cheng@gmail.com>
Subject: Re: [PATCH v2] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

I think it's better to move 'get_non_overloaded_instance' into function_base.

+      /* To avoid API conflicting, we use void return type and void argument
+ for the overloaded function register, like aarch64-sve.  */

Plz rewrite the comments, don't mention aarch64 sve.

Could you run your rvv intrinsic api ci with this patch?
I am worrying that the resolve stuff will destroy the existing APi support.


________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: pan2.li<mailto:pan2.li@intel.com>
Date: 2023-09-12 15:20
To: gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>; kito.cheng<mailto:kito.cheng@gmail.com>
Subject: [PATCH v2] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>

Update in v2:

* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.

Original log:

This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.

However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.

* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.

We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.

gcc/ChangeLog:

* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_instance::get_non_overloaded_instance): New API impl.
(function_builder::add_function): Add overloaded arg.
(function_resolver::function_resolver): New constructor.
(function_builder::add_overloaded_function): New API impl.
(function_resolver::resolve): Ditto.
(function_resolver::lookup): Ditto.
(function_resolver::get_sub_code): Ditto.
(resolve_overloaded_builtin): New function impl.
* config/riscv/riscv-vector-builtins.h:
(class function_resolver): New class.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.

Signed-off-by: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>
---
gcc/config/riscv/riscv-c.cc                   |  36 ++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  35 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
8 files changed, 287 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h

diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..41ecbb48461 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
}
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_instance::get_non_overloaded_instance (unsigned int code,
+ vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}
+
function_builder::function_builder ()
{
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, we use void return type and void argument
+ for the overloaded function register, like aarch64-sve.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance = get_non_overloaded_instance (fun_code,
+      m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..5f8f7a97315 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -256,6 +256,10 @@ public:
   tree get_return_type () const;
   tree get_arg_type (unsigned opno) const;
+  function_instance * get_non_overloaded_instance (unsigned int,
+    vec<tree, va_gc> &arglist)
+    const;
+
   /* The properties of the function.  (The explicit "enum"s are required
      for gengtype.)  */
   const char *base_name;
@@ -277,6 +281,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +294,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -462,6 +468,29 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +515,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+ size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+      size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
--
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-11  7:57 [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic pan2.li
  2023-09-11  8:06 ` juzhe.zhong
  2023-09-12  7:20 ` [PATCH v2] " pan2.li
@ 2023-09-12  8:46 ` pan2.li
  2023-09-12  8:56   ` juzhe.zhong
                     ` (3 more replies)
  2 siblings, 4 replies; 22+ messages in thread
From: pan2.li @ 2023-09-12  8:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, pan2.li, yanzhang.wang, kito.cheng

From: Pan Li <pan2.li@intel.com>

Update in v3:

* Rewrite comment for overloaded function add.
* Move get_non_overloaded_instance to function_base.

Update in v2:

* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.

Original log:

This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.

However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.

* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.

We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.

gcc/ChangeLog:

	* config/riscv/riscv-c.cc
	(riscv_resolve_overloaded_builtin): New function for the hook.
	(riscv_register_pragmas): Register the hook
	* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
	* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
	Register overloaded function.
	(struct overloaded_base): New struct for overloaded shape.
	(struct non_overloaded_base): New struct for non overloaded shape.
	(struct move_def): Inherit overloaded shape.
	* config/riscv/riscv-vector-builtins.cc
	(function_base::get_non_overloaded_instance): New API impl.
	(function_builder::add_function): Add overloaded arg.
	(function_resolver::function_resolver): New constructor.
	(function_builder::add_overloaded_function): New API impl.
	(function_resolver::resolve): Ditto.
	(function_resolver::lookup): Ditto.
	(function_resolver::get_sub_code): Ditto.
	(resolve_overloaded_builtin): New function impl.
	* config/riscv/riscv-vector-builtins.h:
	(class function_resolver): New class.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
	* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
	* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv-c.cc                   |  36 ++++
 gcc/config/riscv/riscv-protos.h               |   1 +
 .../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
 gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
 gcc/config/riscv/riscv-vector-builtins.h      |  36 +++-
 .../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
 .../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
 .../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
 8 files changed, 288 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h

diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
 }
 
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+				  void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+							     arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+				  fndecl);
+}
+
 /* Implement REGISTER_TARGET_PRAGMAS.  */
 
 void
 riscv_register_pragmas (void)
 {
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
 }
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
 bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 bool legitimize_move (rtx, rtx);
 void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
 			 argument_types);
 }
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
 };
 
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
 /* vsetvl_def class.  */
 struct vsetvl_def : public build_base
 {
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
 };
 
 /* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
 {
   char *get_name (function_builder &b, const function_instance &instance,
 		  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..4f6fbdc3e28 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
 
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
 };
 
 /* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
 }
 
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+					    vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+	continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+	{
+	  if (k >= arglist.length ())
+	    break;
+
+	  if (TYPE_MODE (instance.get_arg_type (k))
+	    != TYPE_MODE (TREE_TYPE (arglist[k])))
+	    break;
+	}
+
+	if (args[k].base_type == NUM_BASE_TYPES)
+	  return &rfun->instance;
+    }
+
+  return NULL;
+}
+
 function_builder::function_builder ()
 {
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
 registered_function &
 function_builder::add_function (const function_instance &instance,
 				const char *name, tree fntype, tree attrs,
-				bool placeholder_p)
+				bool placeholder_p,
+				bool overloaded_p = false)
 {
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
 
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
 }
 
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+					   const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, take void return type and void argument
+	 for the overloaded function.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+		    true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
 function_call_info::function_call_info (location_t location_in,
 					const function_instance &instance_in,
 					tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
 {}
 
+function_resolver::function_resolver (location_t location,
+				      const function_instance &instance,
+				      tree fndecl,
+				      vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
 /* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
 void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
 }
 
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance
+    = base->get_non_overloaded_instance (fun_code, m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
 inline hashval_t
 registered_function_hasher::hash (value_type value)
 {
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
 			   TREE_TYPE (rfn.decl), nargs, args).check ();
 }
 
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+			    vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
 function_instance
 get_read_vl_instance (void)
 {
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..e20f0f14ce4 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
 			    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+				const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
 
   registered_function &add_function (const function_instance &, const char *,
-				     tree, tree, bool);
+				     tree, tree, bool, bool);
 
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -424,6 +426,11 @@ public:
   /* 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;
+
+  /* Return the non-overloaded function instance from the registered
+     function table if success, or NULL will be returned.  */
+  virtual function_instance * get_non_overloaded_instance (
+    unsigned int, vec<tree, va_gc> &arglist) const;
 };
 
 /* A class for checking that the semantic constraints on a function call are
@@ -462,6 +469,29 @@ private:
   tree *m_args;
 };
 
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+		     vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
 /* Classifies functions into "shapes" base on:
 
    - Base name of the intrinsic function.
@@ -486,6 +516,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
 };
 
 extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+				 size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+				     size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  8:46 ` [PATCH v3] " pan2.li
@ 2023-09-12  8:56   ` juzhe.zhong
  2023-09-15  2:02   ` juzhe.zhong
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 22+ messages in thread
From: juzhe.zhong @ 2023-09-12  8:56 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: pan2.li, yanzhang.wang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 19924 bytes --]

It looks reasonable to me now.
But let's wait for kito's more comments.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-09-12 16:46
To: gcc-patches
CC: juzhe.zhong; pan2.li; yanzhang.wang; kito.cheng
Subject: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com>
 
Update in v3:
 
* Rewrite comment for overloaded function add.
* Move get_non_overloaded_instance to function_base.
 
Update in v2:
 
* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.
 
Original log:
 
This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.
 
However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.
 
* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.
 
We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.
 
gcc/ChangeLog:
 
* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_base::get_non_overloaded_instance): New API impl.
(function_builder::add_function): Add overloaded arg.
(function_resolver::function_resolver): New constructor.
(function_builder::add_overloaded_function): New API impl.
(function_resolver::resolve): Ditto.
(function_resolver::lookup): Ditto.
(function_resolver::get_sub_code): Ditto.
(resolve_overloaded_builtin): New function impl.
* config/riscv/riscv-vector-builtins.h:
(class function_resolver): New class.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
---
gcc/config/riscv/riscv-c.cc                   |  36 ++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  36 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
8 files changed, 288 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
 
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..4f6fbdc3e28 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
}
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}
+
function_builder::function_builder ()
{
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, take void return type and void argument
+ for the overloaded function.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance
+    = base->get_non_overloaded_instance (fun_code, m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..e20f0f14ce4 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -424,6 +426,11 @@ public:
   /* 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;
+
+  /* Return the non-overloaded function instance from the registered
+     function table if success, or NULL will be returned.  */
+  virtual function_instance * get_non_overloaded_instance (
+    unsigned int, vec<tree, va_gc> &arglist) const;
};
/* A class for checking that the semantic constraints on a function call are
@@ -462,6 +469,29 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +516,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+ size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+      size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  8:46 ` [PATCH v3] " pan2.li
  2023-09-12  8:56   ` juzhe.zhong
@ 2023-09-15  2:02   ` juzhe.zhong
       [not found]   ` <202309151002555436188@rivai.ai>
  2023-09-15  2:29   ` Lehua Ding
  3 siblings, 0 replies; 22+ messages in thread
From: juzhe.zhong @ 2023-09-15  2:02 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: pan2.li, yanzhang.wang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 21587 bytes --]

Sorry for comment again.

I am not happy with current get_non_overloaeded_instance function.

I think the searching approach is very in-effective:

+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}


Instead, I think we should build up a table which map non-overloaded function according to the arguments so that we could get the "instance" effectively.

E.g. For vint8mf8_t tumu vadd intrinsic the instance is like this:
function_instance ("vadd", bases::vadd, shapes::alu,
          iu_ops[VECTOR_TYPE_vuint8mf8_t], PRED_TYPE_tumu, &iu_vvv_ops);

Since the get_nonoverloaed_instance is already the function of the class BASE. 
So, The first 3 arguments "vadd", bases::vadd, shapes::alu
should already known since it is a known function_base.

The last 3 arguments may need some elegant analysis or map table to quickly grep.

So, I think we should consider this framework seriously.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-09-12 16:46
To: gcc-patches
CC: juzhe.zhong; pan2.li; yanzhang.wang; kito.cheng
Subject: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com>
 
Update in v3:
 
* Rewrite comment for overloaded function add.
* Move get_non_overloaded_instance to function_base.
 
Update in v2:
 
* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.
 
Original log:
 
This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.
 
However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.
 
* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.
 
We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.
 
gcc/ChangeLog:
 
* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_base::get_non_overloaded_instance): New API impl.
(function_builder::add_function): Add overloaded arg.
(function_resolver::function_resolver): New constructor.
(function_builder::add_overloaded_function): New API impl.
(function_resolver::resolve): Ditto.
(function_resolver::lookup): Ditto.
(function_resolver::get_sub_code): Ditto.
(resolve_overloaded_builtin): New function impl.
* config/riscv/riscv-vector-builtins.h:
(class function_resolver): New class.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
---
gcc/config/riscv/riscv-c.cc                   |  36 ++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  36 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
8 files changed, 288 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
 
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..4f6fbdc3e28 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
}
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}
+
function_builder::function_builder ()
{
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, take void return type and void argument
+ for the overloaded function.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance
+    = base->get_non_overloaded_instance (fun_code, m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..e20f0f14ce4 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -424,6 +426,11 @@ public:
   /* 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;
+
+  /* Return the non-overloaded function instance from the registered
+     function table if success, or NULL will be returned.  */
+  virtual function_instance * get_non_overloaded_instance (
+    unsigned int, vec<tree, va_gc> &arglist) const;
};
/* A class for checking that the semantic constraints on a function call are
@@ -462,6 +469,29 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +516,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+ size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+      size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
       [not found]   ` <202309151002555436188@rivai.ai>
@ 2023-09-15  2:20     ` juzhe.zhong
  2023-09-15  2:24       ` Li, Pan2
  0 siblings, 1 reply; 22+ messages in thread
From: juzhe.zhong @ 2023-09-15  2:20 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: pan2.li, yanzhang.wang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 22191 bytes --]

More information:

For PRED_TYPE_tumu, it's easy to analyze, just need to count how many arguments in the arglist.
If arglist has 5 arguments (mask, merge, op1, op2, len) Then it must be TUMU.

What I mean is that we should be able to quickly to compute the arguments of the construction of the function_instance.
Then we can get the non-overloaeded function.



juzhe.zhong@rivai.ai
 
From: juzhe.zhong@rivai.ai
Date: 2023-09-15 10:02
To: pan2.li; gcc-patches
CC: pan2.li; yanzhang.wang; kito.cheng
Subject: Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
Sorry for comment again.

I am not happy with current get_non_overloaeded_instance function.

I think the searching approach is very in-effective:

+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}


Instead, I think we should build up a table which map non-overloaded function according to the arguments so that we could get the "instance" effectively.

E.g. For vint8mf8_t tumu vadd intrinsic the instance is like this:
function_instance ("vadd", bases::vadd, shapes::alu,
          iu_ops[VECTOR_TYPE_vuint8mf8_t], PRED_TYPE_tumu, &iu_vvv_ops);

Since the get_nonoverloaed_instance is already the function of the class BASE. 
So, The first 3 arguments "vadd", bases::vadd, shapes::alu
should already known since it is a known function_base.

The last 3 arguments may need some elegant analysis or map table to quickly grep.

So, I think we should consider this framework seriously.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-09-12 16:46
To: gcc-patches
CC: juzhe.zhong; pan2.li; yanzhang.wang; kito.cheng
Subject: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com>
 
Update in v3:
 
* Rewrite comment for overloaded function add.
* Move get_non_overloaded_instance to function_base.
 
Update in v2:
 
* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.
 
Original log:
 
This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.
 
However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.
 
* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.
 
We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.
 
gcc/ChangeLog:
 
* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_base::get_non_overloaded_instance): New API impl.
(function_builder::add_function): Add overloaded arg.
(function_resolver::function_resolver): New constructor.
(function_builder::add_overloaded_function): New API impl.
(function_resolver::resolve): Ditto.
(function_resolver::lookup): Ditto.
(function_resolver::get_sub_code): Ditto.
(resolve_overloaded_builtin): New function impl.
* config/riscv/riscv-vector-builtins.h:
(class function_resolver): New class.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
---
gcc/config/riscv/riscv-c.cc                   |  36 ++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  36 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
8 files changed, 288 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
 
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..4f6fbdc3e28 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
}
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}
+
function_builder::function_builder ()
{
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, take void return type and void argument
+ for the overloaded function.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance
+    = base->get_non_overloaded_instance (fun_code, m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..e20f0f14ce4 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -424,6 +426,11 @@ public:
   /* 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;
+
+  /* Return the non-overloaded function instance from the registered
+     function table if success, or NULL will be returned.  */
+  virtual function_instance * get_non_overloaded_instance (
+    unsigned int, vec<tree, va_gc> &arglist) const;
};
/* A class for checking that the semantic constraints on a function call are
@@ -462,6 +469,29 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +516,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+ size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+      size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-15  2:20     ` juzhe.zhong
@ 2023-09-15  2:24       ` Li, Pan2
  0 siblings, 0 replies; 22+ messages in thread
From: Li, Pan2 @ 2023-09-15  2:24 UTC (permalink / raw)
  To: juzhe.zhong, gcc-patches; +Cc: Wang, Yanzhang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 23246 bytes --]

Thanks Juzhe for comments, got the point and will have a try for hashmap liked approach to get the non-overloaded later in PATCH v4. Sorry for that in the middle of something.

Pan

From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Friday, September 15, 2023 10:21 AM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Li, Pan2 <pan2.li@intel.com>; Wang, Yanzhang <yanzhang.wang@intel.com>; kito.cheng <kito.cheng@gmail.com>
Subject: Re: Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

More information:

For PRED_TYPE_tumu, it's easy to analyze, just need to count how many arguments in the arglist.
If arglist has 5 arguments (mask, merge, op1, op2, len) Then it must be TUMU.

What I mean is that we should be able to quickly to compute the arguments of the construction of the function_instance.
Then we can get the non-overloaeded function.

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>
Date: 2023-09-15 10:02
To: pan2.li<mailto:pan2.li@intel.com>; gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>; kito.cheng<mailto:kito.cheng@gmail.com>
Subject: Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
Sorry for comment again.

I am not happy with current get_non_overloaeded_instance function.

I think the searching approach is very in-effective:

+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}


Instead, I think we should build up a table which map non-overloaded function according to the arguments so that we could get the "instance" effectively.

E.g. For vint8mf8_t tumu vadd intrinsic the instance is like this:
function_instance ("vadd", bases::vadd, shapes::alu,
          iu_ops[VECTOR_TYPE_vuint8mf8_t], PRED_TYPE_tumu, &iu_vvv_ops);

Since the get_nonoverloaed_instance is already the function of the class BASE.
So, The first 3 arguments "vadd", bases::vadd, shapes::alu
should already known since it is a known function_base.

The last 3 arguments may need some elegant analysis or map table to quickly grep.

So, I think we should consider this framework seriously.

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: pan2.li<mailto:pan2.li@intel.com>
Date: 2023-09-12 16:46
To: gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>; kito.cheng<mailto:kito.cheng@gmail.com>
Subject: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
From: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>

Update in v3:

* Rewrite comment for overloaded function add.
* Move get_non_overloaded_instance to function_base.

Update in v2:

* Add get_non_overloaded_instance for function instance.
* Fix overload check for policy function.
* Enrich the test cases check.

Original log:

This patch would like add the framework to support the RVV overloaded
intrinsic API in riscv-xxx-xxx-gcc, like riscv-xxx-xxx-g++ did.

However, it almost leverage the hook TARGET_RESOLVE_OVERLOADED_BUILTIN
with below steps.

* Register overloaded functions.
* Add function_resolver for overloaded function resolving.
* Add resolve API for function shape with default implementation.
* Implement HOOK for navigating the overloaded API to non-overloaded API.

We validated this framework by the vmv_v intrinsic API(s), and we will
add more intrins API support in the underlying patches.

gcc/ChangeLog:

* config/riscv/riscv-c.cc
(riscv_resolve_overloaded_builtin): New function for the hook.
(riscv_register_pragmas): Register the hook
* config/riscv/riscv-protos.h (resolve_overloaded_builtin): New decl.
* config/riscv/riscv-vector-builtins-shapes.cc (build_one):
Register overloaded function.
(struct overloaded_base): New struct for overloaded shape.
(struct non_overloaded_base): New struct for non overloaded shape.
(struct move_def): Inherit overloaded shape.
* config/riscv/riscv-vector-builtins.cc
(function_base::get_non_overloaded_instance): New API impl.
(function_builder::add_function): Add overloaded arg.
(function_resolver::function_resolver): New constructor.
(function_builder::add_overloaded_function): New API impl.
(function_resolver::resolve): Ditto.
(function_resolver::lookup): Ditto.
(function_resolver::get_sub_code): Ditto.
(resolve_overloaded_builtin): New function impl.
* config/riscv/riscv-vector-builtins.h:
(class function_resolver): New class.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c: New test.
* gcc.target/riscv/rvv/base/overloaded_vmv_v.h: New test.

Signed-off-by: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>
---
gcc/config/riscv/riscv-c.cc                   |  36 ++++
gcc/config/riscv/riscv-protos.h               |   1 +
.../riscv/riscv-vector-builtins-shapes.cc     |  20 ++-
gcc/config/riscv/riscv-vector-builtins.cc     | 155 +++++++++++++++++-
gcc/config/riscv/riscv-vector-builtins.h      |  36 +++-
.../riscv/rvv/base/overloaded_rv32_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_rv64_vmv_v.c    |   8 +
.../riscv/rvv/base/overloaded_vmv_v.h         |  27 +++
8 files changed, 288 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h

diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 283052ae313..060edd3129d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -220,11 +220,47 @@ riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl,
   gcc_unreachable ();
}
+/* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
+static tree
+riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl,
+   void *uncast_arglist)
+{
+  vec<tree, va_gc> empty = {};
+  location_t loc = (location_t) uncast_location;
+  vec<tree, va_gc> *arglist = (vec<tree, va_gc> *) uncast_arglist;
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
+  tree new_fndecl = NULL_TREE;
+
+  if (!arglist)
+    arglist = &empty;
+
+  switch (code & RISCV_BUILTIN_CLASS)
+    {
+    case RISCV_BUILTIN_GENERAL:
+      break;
+    case RISCV_BUILTIN_VECTOR:
+      new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode,
+      arglist);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (new_fndecl == NULL_TREE)
+    return new_fndecl;
+
+  return build_function_call_vec (loc, vNULL, new_fndecl, arglist, NULL,
+   fndecl);
+}
+
/* Implement REGISTER_TARGET_PRAGMAS.  */
void
riscv_register_pragmas (void)
{
+  targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin;
   targetm.check_builtin_call = riscv_check_builtin_call;
+
   c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic);
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6dbf6b9f943..5d2492dd031 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -381,6 +381,7 @@ 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 *);
+tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *);
bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
bool legitimize_move (rtx, rtx);
void emit_vlmax_vsetvl (machine_mode, rtx);
diff --git a/gcc/config/riscv/riscv-vector-builtins-shapes.cc b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
index f8fdec863e6..1c1a2cc9488 100644
--- a/gcc/config/riscv/riscv-vector-builtins-shapes.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-shapes.cc
@@ -49,6 +49,8 @@ build_one (function_builder &b, const function_group_info &group,
     group.ops_infos.types[vec_type_idx].index);
   b.allocate_argument_types (function_instance, argument_types);
   b.apply_predication (function_instance, return_type, argument_types);
+
+  b.add_overloaded_function (function_instance, *group.shape);
   b.add_unique_function (function_instance, (*group.shape), return_type,
argument_types);
}
@@ -87,6 +89,22 @@ struct build_base : public function_shape
   }
};
+struct overloaded_base : public build_base
+{
+  tree resolve (function_resolver &r) const override
+  {
+    return r.lookup ();
+  }
+};
+
+struct non_overloaded_base : public build_base
+{
+  tree resolve (function_resolver &) const override
+  {
+    gcc_unreachable ();
+  }
+};
+
/* vsetvl_def class.  */
struct vsetvl_def : public build_base
{
@@ -525,7 +543,7 @@ struct narrow_alu_def : public build_base
};
/* move_def class. Handle vmv.v.v/vmv.v.x.  */
-struct move_def : public build_base
+struct move_def : public overloaded_base
{
   char *get_name (function_builder &b, const function_instance &instance,
  bool overloaded_p) const override
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 6d99f970ead..4f6fbdc3e28 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -80,6 +80,10 @@ public:
   /* The decl itself.  */
   tree GTY ((skip)) decl;
+
+  /* True if the decl represents an overloaded function that needs to be
+     resolved by function_resolver.  */
+  bool overloaded_p;
};
/* Hash traits for registered_function.  */
@@ -3196,6 +3200,77 @@ function_instance::could_trap_p () const
   return false;
}
+/* Try to get the non-overloaded function instance.
+   After we register the overloaded the functions, the registered functions
+   table may look like:
+
+   +--------+---------------------------+-------------------+
+   | index  | name                      | kind              |
+   +--------+---------------------------+-------------------+
+   | 124733 | __riscv_vmv_v             | Overloaded        | <- Hook fun code
+   +--------+---------------------------+-------------------+
+   | 124735 | __riscv_vmv_v_v_i8mf8     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124737 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124739 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124741 | __riscv_vmv_v_v_i8mf4     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124743 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124745 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124747 | __riscv_vmv_v_v_i8mf2     | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124749 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+   | 124751 | __riscv_vmv_v             | Overloaded        |
+   +--------+---------------------------+-------------------+
+   | 124753 | __riscv_vmv_v_v_i8m1      | Non-overloaded    |
+   +--------+---------------------------+-------------------+
+   | 124755 | __riscv_vmv_v             | Placeholder       |
+   +--------+---------------------------+-------------------+
+
+   When we resolve the overloaded API from the hook, we always get the first
+   function code of one API group (aka vmv_v as above table). We will search
+   start from that index to find the only one non-overloaded API with exactly
+   the same arglist. Or NULL instance will be returned.
+ */
+function_instance *
+function_base::get_non_overloaded_instance (unsigned int code,
+     vec<tree, va_gc> &arglist) const
+{
+  unsigned int code_limit = vec_safe_length (registered_functions);
+
+  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
+    {
+      registered_function *rfun = (*registered_functions)[fun_code];
+      function_instance instance = rfun->instance;
+
+      if (rfun->overloaded_p)
+ continue;
+
+      unsigned k;
+      const rvv_arg_type_info *args = instance.op_info->args;
+
+      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
+ {
+   if (k >= arglist.length ())
+     break;
+
+   if (TYPE_MODE (instance.get_arg_type (k))
+     != TYPE_MODE (TREE_TYPE (arglist[k])))
+     break;
+ }
+
+ if (args[k].base_type == NUM_BASE_TYPES)
+   return &rfun->instance;
+    }
+
+  return NULL;
+}
+
function_builder::function_builder ()
{
   m_direct_overloads = lang_GNU_CXX ();
@@ -3357,7 +3432,8 @@ function_builder::get_attributes (const function_instance &instance)
registered_function &
function_builder::add_function (const function_instance &instance,
const char *name, tree fntype, tree attrs,
- bool placeholder_p)
+ bool placeholder_p,
+ bool overloaded_p = false)
{
   unsigned int code = vec_safe_length (registered_functions);
   code = (code << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_VECTOR;
@@ -3383,6 +3459,7 @@ function_builder::add_function (const function_instance &instance,
   registered_function &rfn = *ggc_alloc<registered_function> ();
   rfn.instance = instance;
   rfn.decl = decl;
+  rfn.overloaded_p = overloaded_p;
   vec_safe_push (registered_functions, &rfn);
   return rfn;
@@ -3432,6 +3509,26 @@ function_builder::add_unique_function (const function_instance &instance,
   obstack_free (&m_string_obstack, name);
}
+void
+function_builder::add_overloaded_function (const function_instance &instance,
+    const function_shape *shape)
+{
+  if (!check_required_extensions (instance))
+    return;
+
+  char *name = shape->get_name (*this, instance, true);
+
+  if (name)
+    {
+      /* To avoid API conflicting, take void return type and void argument
+ for the overloaded function.  */
+      tree fntype = build_function_type (void_type_node, void_list_node);
+      add_function (instance, name, fntype, NULL_TREE, m_direct_overloads,
+     true);
+      obstack_free (&m_string_obstack, name);
+    }
+}
+
function_call_info::function_call_info (location_t location_in,
const function_instance &instance_in,
tree fndecl_in)
@@ -3852,6 +3949,13 @@ function_checker::function_checker (location_t location,
     m_nargs (nargs), m_args (args)
{}
+function_resolver::function_resolver (location_t location,
+       const function_instance &instance,
+       tree fndecl,
+       vec<tree, va_gc> &arglist)
+  : function_call_info (location, instance, fndecl), m_arglist (arglist)
+{}
+
/* Report that LOCATION has a call to FNDECL in which argument ARGNO
    was not an integer constant expression.  ARGNO counts from zero.  */
void
@@ -3967,6 +4071,39 @@ function_checker::check ()
   return shape->check (*this);
}
+unsigned int
+function_resolver::get_sub_code ()
+{
+  unsigned int fun_code = DECL_MD_FUNCTION_CODE (fndecl);
+
+  return fun_code >> RISCV_BUILTIN_SHIFT;
+}
+
+tree
+function_resolver::resolve ()
+{
+  return shape->resolve (*this);
+}
+
+tree
+function_resolver::lookup ()
+{
+  unsigned int fun_code = get_sub_code ();
+  function_instance *instance
+    = base->get_non_overloaded_instance (fun_code, m_arglist);
+
+  if (!instance)
+    return NULL_TREE;
+
+  hashval_t hash = instance->hash ();
+  registered_function *rfun = function_table->find_with_hash (*instance, hash);
+
+  if (!rfun)
+    return NULL_TREE;
+
+  return rfun->decl;
+}
+
inline hashval_t
registered_function_hasher::hash (value_type value)
{
@@ -4196,6 +4333,22 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code,
   TREE_TYPE (rfn.decl), nargs, args).check ();
}
+tree
+resolve_overloaded_builtin (location_t loc, unsigned int code,
+     vec<tree, va_gc> *arglist)
+{
+  if (code >= vec_safe_length (registered_functions))
+    return NULL_TREE;
+
+  const registered_function *rfun = (*registered_functions)[code];
+
+  if (!rfun || !rfun->overloaded_p)
+    return NULL_TREE;
+
+  return function_resolver (loc, rfun->instance, rfun->decl, *arglist)
+    .resolve ();
+}
+
function_instance
get_read_vl_instance (void)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index e358a8e4d91..e20f0f14ce4 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -277,6 +277,8 @@ public:
   void apply_predication (const function_instance &, tree, vec<tree> &) const;
   void add_unique_function (const function_instance &, const function_shape *,
    tree, vec<tree> &);
+  void add_overloaded_function (const function_instance &,
+ const function_shape *);
   void register_function_group (const function_group_info &);
   void append_name (const char *);
   void append_base_name (const char *);
@@ -288,7 +290,7 @@ private:
   tree get_attributes (const function_instance &);
   registered_function &add_function (const function_instance &, const char *,
-      tree, tree, bool);
+      tree, tree, bool, bool);
   /* True if we should create a separate decl for each instance of an
      overloaded function, instead of using function_builder.  */
@@ -424,6 +426,11 @@ public:
   /* 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;
+
+  /* Return the non-overloaded function instance from the registered
+     function table if success, or NULL will be returned.  */
+  virtual function_instance * get_non_overloaded_instance (
+    unsigned int, vec<tree, va_gc> &arglist) const;
};
/* A class for checking that the semantic constraints on a function call are
@@ -462,6 +469,29 @@ private:
   tree *m_args;
};
+/* A class for resolving an overloaded function call.  */
+class function_resolver : public function_call_info
+{
+public:
+  function_resolver (location_t, const function_instance &, tree,
+      vec<tree, va_gc> &);
+
+  /* Resolve the correlated non-overloaded function from the
+     the registered_functions table.  */
+  tree resolve ();
+
+  /* Lookup the non-overloaded function from the registered
+     function table.  */
+  tree lookup ();
+
+  /* Return the sub code of the fndecl.  */
+  unsigned int get_sub_code ();
+
+private:
+  /* The arguments to the overloaded function.  */
+  vec<tree, va_gc> &m_arglist;
+};
+
/* Classifies functions into "shapes" base on:
    - Base name of the intrinsic function.
@@ -486,6 +516,10 @@ public:
   /* Check whether the given call is semantically valid.  Return true
    if it is, otherwise report an error and return false.  */
   virtual bool check (function_checker &) const { return true; }
+
+  /* Try to resolve the overloaded call.  Return the non-overloaded
+     function decl on success and NULL_TREE on failure.  */
+  virtual tree resolve (function_resolver &) const { return NULL_TREE; };
};
extern const char *const operand_suffixes[NUM_OP_TYPES];
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
new file mode 100644
index 00000000000..56154da155b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv32_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv_zvfh -mabi=ilp32 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
new file mode 100644
index 00000000000..f4a63c9585d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_rv64_vmv_v.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "overloaded_vmv_v.h"
+
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e32,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e16,\s*m1,\s*ta,\s*ma} 2 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+zero,\s*[ax][0-9]+,\s*e8,\s*m4,\s*tu,\s*ma} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
new file mode 100644
index 00000000000..8756c5e17b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/overloaded_vmv_v.h
@@ -0,0 +1,27 @@
+#include "riscv_vector.h"
+
+vint32m1_t test_vmv_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vfloat16m1_t test_vmv_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v (src, vl);
+}
+
+vint8m4_t test_vmv_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+ size_t vl) {
+  return __riscv_vmv_v_tu (maskedoff, src, vl);
+}
+
+vint32m1_t test_vmv_non_overloaded_0 (vint32m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_i32m1 (src, vl);
+}
+
+vfloat16m1_t test_vmv_non_overloaded_1 (vfloat16m1_t src, size_t vl) {
+  return __riscv_vmv_v_v_f16m1 (src, vl);
+}
+
+vint8m4_t test_vmv_non_overloaded_2 (vint8m4_t maskedoff, vint8m4_t src,
+      size_t vl) {
+  return __riscv_vmv_v_v_i8m4_tu (maskedoff, src, vl);
+}
--
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-12  8:46 ` [PATCH v3] " pan2.li
                     ` (2 preceding siblings ...)
       [not found]   ` <202309151002555436188@rivai.ai>
@ 2023-09-15  2:29   ` Lehua Ding
  2023-09-15  2:32     ` Li, Pan2
  3 siblings, 1 reply; 22+ messages in thread
From: Lehua Ding @ 2023-09-15  2:29 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: yanzhang.wang, kito.cheng, juzhe.zhong

Hi Pan,

> +function_instance *
> +function_base::get_non_overloaded_instance (unsigned int code,
> +					    vec<tree, va_gc> &arglist) const
> +{
> +  unsigned int code_limit = vec_safe_length (registered_functions);
> +
> +  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
> +    {
> +      registered_function *rfun = (*registered_functions)[fun_code];
> +      function_instance instance = rfun->instance;
> +
> +      if (rfun->overloaded_p)
> +	continue;
> +
> +      unsigned k;
> +      const rvv_arg_type_info *args = instance.op_info->args;
> +
> +      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
> +	{
> +	  if (k >= arglist.length ())
> +	    break;

Can we fast continue if args length not equal arglist length before this 
loop:

   if (args lengh != arglist.length ())
     continue;

   for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
   {
     ...

-- 
Best,
Lehua


^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic
  2023-09-15  2:29   ` Lehua Ding
@ 2023-09-15  2:32     ` Li, Pan2
  0 siblings, 0 replies; 22+ messages in thread
From: Li, Pan2 @ 2023-09-15  2:32 UTC (permalink / raw)
  To: Lehua Ding, gcc-patches; +Cc: Wang, Yanzhang, kito.cheng, juzhe.zhong

Thanks Lehua, actually Yes.

Consider we will have a try for hashmap way and will keep you posted.

Pan

-----Original Message-----
From: Lehua Ding <lehua.ding@rivai.ai> 
Sent: Friday, September 15, 2023 10:29 AM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: Wang, Yanzhang <yanzhang.wang@intel.com>; kito.cheng@gmail.com; juzhe.zhong@rivai.ai
Subject: Re: [PATCH v3] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic

Hi Pan,

> +function_instance *
> +function_base::get_non_overloaded_instance (unsigned int code,
> +					    vec<tree, va_gc> &arglist) const
> +{
> +  unsigned int code_limit = vec_safe_length (registered_functions);
> +
> +  for (unsigned fun_code = code; fun_code < code_limit; fun_code++)
> +    {
> +      registered_function *rfun = (*registered_functions)[fun_code];
> +      function_instance instance = rfun->instance;
> +
> +      if (rfun->overloaded_p)
> +	continue;
> +
> +      unsigned k;
> +      const rvv_arg_type_info *args = instance.op_info->args;
> +
> +      for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
> +	{
> +	  if (k >= arglist.length ())
> +	    break;

Can we fast continue if args length not equal arglist length before this 
loop:

   if (args lengh != arglist.length ())
     continue;

   for (k = 0; args[k].base_type != NUM_BASE_TYPES; k++)
   {
     ...

-- 
Best,
Lehua


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2023-09-15  2:32 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-11  7:57 [PATCH v1] RISC-V: Implement RESOLVE_OVERLOADED_BUILTIN for RVV intrinsic pan2.li
2023-09-11  8:06 ` juzhe.zhong
2023-09-11  9:04   ` Kito Cheng
2023-09-11  9:13     ` juzhe.zhong
2023-09-11 12:09       ` Li, Pan2
     [not found]       ` <03D4A8A613CD8015+D14577CD-36C5-493B-8B7E-1D83914B5C17@rivai.ai>
2023-09-11 12:26         ` Li, Pan2
2023-09-11 13:06           ` 钟居哲
2023-09-11 15:24             ` Li, Pan2
2023-09-11 23:19               ` 钟居哲
2023-09-12  1:20                 ` Li, Pan2
2023-09-12  1:29                   ` juzhe.zhong
2023-09-12  1:50                     ` Li, Pan2
2023-09-12  7:20 ` [PATCH v2] " pan2.li
2023-09-12  7:46   ` juzhe.zhong
2023-09-12  7:53     ` Li, Pan2
2023-09-12  8:46 ` [PATCH v3] " pan2.li
2023-09-12  8:56   ` juzhe.zhong
2023-09-15  2:02   ` juzhe.zhong
     [not found]   ` <202309151002555436188@rivai.ai>
2023-09-15  2:20     ` juzhe.zhong
2023-09-15  2:24       ` Li, Pan2
2023-09-15  2:29   ` Lehua Ding
2023-09-15  2:32     ` Li, Pan2

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).