diff mbox series

[03/15] arm: [MVE intrinsics] Cleanup arm-mve-builtins-functions.h

Message ID 20240711214305.3193022-3-christophe.lyon@linaro.org
State New
Headers show
Series [01/15] arm: [MVE intrinsics] improve comment for orrq shape | expand

Commit Message

Christophe Lyon July 11, 2024, 9:42 p.m. UTC
This patch brings no functional change but removes some code
duplication in arm-mve-builtins-functions.h and makes it easier to
read and maintain.

It introduces a new expand_unspec () member of
unspec_based_mve_function_base and makes a few classes inherit from it
instead of function_base.

This adds 3 new members containing the unspec codes for signed-int,
unsigned-int and floating-point intrinsics (no mode, no predicate).
Depending on the derived class, these will be used instead of the 3
similar RTX codes.

The new expand_unspec () handles all the possible unspecs, some of
which maybe not be supported by a given intrinsics family: such code
paths won't be used in that case.  Similarly codes specific to a
family (RTX, or PRED_p for instance) should be handled by the caller
of expand_unspec ().

Thanks to this, expand () for unspec_based_mve_function_exact_insn,
unspec_mve_function_exact_insn, unspec_mve_function_exact_insn_pred_p,
unspec_mve_function_exact_insn_vshl no longer duplicate a lot of code.

The patch also make most of PRED_m and PRED_x handling use the same
code.

2024-07-11  Christophe Lyon  <christophe.lyon@linaro.org>

	gcc/
	* config/arm/arm-mve-builtins-functions.h
	(unspec_based_mve_function_base): Add m_unspec_for_sint,
	m_unspec_for_uint, m_unspec_for_fp and expand_unspec members.
	(unspec_based_mve_function_exact_insn): Inherit from
	unspec_based_mve_function_base and use expand_unspec.
	(unspec_mve_function_exact_insn): Likewise.
	(unspec_mve_function_exact_insn_pred_p): Likewise.
	(unspec_mve_function_exact_insn_vshl): Likewise.
	(unspec_based_mve_function_exact_insn_vcmp): Initialize new
	inherited members.
	(unspec_mve_function_exact_insn_rot): Merge PRED_m and PRED_x
	handling.
	(unspec_mve_function_exact_insn_vmull): Likewise.
	(unspec_mve_function_exact_insn_vmull_poly): Likewise.
---
 gcc/config/arm/arm-mve-builtins-functions.h | 607 +++++++-------------
 1 file changed, 211 insertions(+), 396 deletions(-)

Comments

Andre Vieira (lists) Aug. 2, 2024, 4:14 p.m. UTC | #1
Hi,

This looks great to me, only one small suggestion, but take it or leave 
it I think it's a matter of preference.

On 11/07/2024 22:42, Christophe Lyon wrote:

> +	    /* No predicate, no suffix.  */
>   	    if (e.type_suffix (0).integer_p)
>   	      if (e.type_suffix (0).unsigned_p)
> -		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
> +		code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, mode);
>   	      else
> -		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
> +		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, mode);
>   	    else
> -	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, e.vector_mode (0));
> +	      code = code_for_mve_q_f (m_unspec_for_fp, mode);
>   	    break;

I'd write this as:
if (e.type_suffix (0).integer_p)
   {
     int unspec = (e.type_suffix (0).unsigned_p
                   ? m_unspec_for_m_uint
                   : m_unspec_for_m_sint);
     code = code_for_mve_q (unspec, unspec, mode);
   }
else
   code = code_for_mve_q_f (m_unspec_for_fp, mode);
break;

And same for similar below ofc.  I have a slight preference to this as 
it makes it clear that both parameters are the same without needing to 
make a more difficult visual comparison and it also makes clear what the 
difference is between the unsigned_p true or false.

Not a strong opinion here though.
Christophe Lyon Aug. 2, 2024, 4:45 p.m. UTC | #2
On Fri, 2 Aug 2024 at 18:14, Andre Vieira (lists)
<andre.simoesdiasvieira@arm.com> wrote:
>
> Hi,
>
> This looks great to me, only one small suggestion, but take it or leave
> it I think it's a matter of preference.
>
> On 11/07/2024 22:42, Christophe Lyon wrote:
>
> > +         /* No predicate, no suffix.  */
> >           if (e.type_suffix (0).integer_p)
> >             if (e.type_suffix (0).unsigned_p)
> > -             code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
> > +             code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, mode);
> >             else
> > -             code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
> > +             code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, mode);
> >           else
> > -           code = code_for_mve_q_m_f (m_unspec_for_m_fp, e.vector_mode (0));
> > +           code = code_for_mve_q_f (m_unspec_for_fp, mode);
> >           break;
>
> I'd write this as:
> if (e.type_suffix (0).integer_p)
>    {
>      int unspec = (e.type_suffix (0).unsigned_p
>                    ? m_unspec_for_m_uint
>                    : m_unspec_for_m_sint);
>      code = code_for_mve_q (unspec, unspec, mode);
>    }
> else
>    code = code_for_mve_q_f (m_unspec_for_fp, mode);
> break;
>
> And same for similar below ofc.  I have a slight preference to this as
> it makes it clear that both parameters are the same without needing to
> make a more difficult visual comparison and it also makes clear what the
> difference is between the unsigned_p true or false.
>
> Not a strong opinion here though.


I think you are right, this goes in the same direction of what this
cleanup intended: remove duplication and make it easier to
read/maintain.

I'll update this patch accordingly.

Thanks,

Christophe
diff mbox series

Patch

diff --git a/gcc/config/arm/arm-mve-builtins-functions.h b/gcc/config/arm/arm-mve-builtins-functions.h
index ac2a731bff4..43c4aaffeb1 100644
--- a/gcc/config/arm/arm-mve-builtins-functions.h
+++ b/gcc/config/arm/arm-mve-builtins-functions.h
@@ -40,17 +40,23 @@  public:
 };
 
 /* An incomplete function_base for functions that have an associated
-   rtx_code for signed integers, unsigned integers and floating-point
-   values for the non-predicated, non-suffixed intrinsic, and unspec
-   codes, with separate codes for signed integers, unsigned integers
-   and floating-point values.  The class simply records information
-   about the mapping for derived classes to use.  */
+   rtx_code or an unspec for signed integers, unsigned integers and
+   floating-point values for the non-predicated, non-suffixed
+   intrinsics, and unspec codes, with separate codes for signed
+   integers, unsigned integers and floating-point values for
+   predicated and/or suffixed intrinsics.  The class simply records
+   information about the mapping for derived classes to use and
+   provides a generic expand_unspec () to avoid duplicating expansion
+   code in derived classes.  */
 class unspec_based_mve_function_base : public function_base
 {
 public:
   CONSTEXPR unspec_based_mve_function_base (rtx_code code_for_sint,
 					    rtx_code code_for_uint,
 					    rtx_code code_for_fp,
+					    int unspec_for_sint,
+					    int unspec_for_uint,
+					    int unspec_for_fp,
 					    int unspec_for_n_sint,
 					    int unspec_for_n_uint,
 					    int unspec_for_n_fp,
@@ -63,6 +69,9 @@  public:
     : m_code_for_sint (code_for_sint),
       m_code_for_uint (code_for_uint),
       m_code_for_fp (code_for_fp),
+      m_unspec_for_sint (unspec_for_sint),
+      m_unspec_for_uint (unspec_for_uint),
+      m_unspec_for_fp (unspec_for_fp),
       m_unspec_for_n_sint (unspec_for_n_sint),
       m_unspec_for_n_uint (unspec_for_n_uint),
       m_unspec_for_n_fp (unspec_for_n_fp),
@@ -83,6 +92,9 @@  public:
   /* The unspec code associated with signed-integer, unsigned-integer
      and floating-point operations respectively.  It covers the cases
      with the _n suffix, and/or the _m predicate.  */
+  int m_unspec_for_sint;
+  int m_unspec_for_uint;
+  int m_unspec_for_fp;
   int m_unspec_for_n_sint;
   int m_unspec_for_n_uint;
   int m_unspec_for_n_fp;
@@ -92,142 +104,146 @@  public:
   int m_unspec_for_m_n_sint;
   int m_unspec_for_m_n_uint;
   int m_unspec_for_m_n_fp;
+
+  rtx expand_unspec (function_expander &e) const;
 };
 
-/* Map the function directly to CODE (UNSPEC, M) where M is the vector
-   mode associated with type suffix 0, except when there is no
-   predicate and no _n suffix, in which case we use the appropriate
-   rtx_code.  This is useful when the basic operation is mapped to a
-   standard RTX code and all other versions use different unspecs.  */
-class unspec_based_mve_function_exact_insn : public unspec_based_mve_function_base
+/* Expand the unspecs, which is common to all intrinsics using
+   unspec_based_mve_function_base.  If some combinations are not
+   supported for an intrinsics family, they should be handled by the
+   caller (and not crash here).  */
+rtx
+unspec_based_mve_function_base::expand_unspec (function_expander &e) const
 {
-public:
-  CONSTEXPR unspec_based_mve_function_exact_insn (rtx_code code_for_sint,
-						  rtx_code code_for_uint,
-						  rtx_code code_for_fp,
-						  int unspec_for_n_sint,
-						  int unspec_for_n_uint,
-						  int unspec_for_n_fp,
-						  int unspec_for_m_sint,
-						  int unspec_for_m_uint,
-						  int unspec_for_m_fp,
-						  int unspec_for_m_n_sint,
-						  int unspec_for_m_n_uint,
-						  int unspec_for_m_n_fp)
-    : unspec_based_mve_function_base (code_for_sint,
-				      code_for_uint,
-				      code_for_fp,
-				      unspec_for_n_sint,
-				      unspec_for_n_uint,
-				      unspec_for_n_fp,
-				      unspec_for_m_sint,
-				      unspec_for_m_uint,
-				      unspec_for_m_fp,
-				      unspec_for_m_n_sint,
-				      unspec_for_m_n_uint,
-				      unspec_for_m_n_fp)
-  {}
-
-  rtx
-  expand (function_expander &e) const override
-  {
-    /* No suffix, no predicate, use the right RTX code.  */
-    if ((e.mode_suffix_id != MODE_n)
-	&& (e.pred == PRED_none))
-      return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint,
-				 m_code_for_fp);
-
+    machine_mode mode = e.vector_mode (0);
     insn_code code;
+
     switch (e.pred)
       {
       case PRED_none:
-	if (e.mode_suffix_id == MODE_n)
-	  /* No predicate, _n suffix.  */
-	  {
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_n (m_unspec_for_n_uint, m_unspec_for_n_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_n (m_unspec_for_n_sint, m_unspec_for_n_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_n_f (m_unspec_for_n_fp, e.vector_mode (0));
-
-	    return e.use_exact_insn (code);
-	  }
-	gcc_unreachable ();
-	break;
-
-      case PRED_m:
 	switch (e.mode_suffix_id)
 	  {
 	  case MODE_none:
-	    /* No suffix, "m" predicate.  */
+	    /* No predicate, no suffix.  */
 	    if (e.type_suffix (0).integer_p)
 	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
+		code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, mode);
 	      else
-		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
+		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, mode);
 	    else
-	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, e.vector_mode (0));
+	      code = code_for_mve_q_f (m_unspec_for_fp, mode);
 	    break;
 
 	  case MODE_n:
-	    /* _n suffix, "m" predicate.  */
+	    /* No predicate, _n suffix.  */
 	    if (e.type_suffix (0).integer_p)
 	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, e.vector_mode (0));
+		code = code_for_mve_q_n (m_unspec_for_n_uint, m_unspec_for_n_uint, mode);
 	      else
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, e.vector_mode (0));
+		code = code_for_mve_q_n (m_unspec_for_n_sint, m_unspec_for_n_sint, mode);
 	    else
-	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, e.vector_mode (0));
+	      code = code_for_mve_q_n_f (m_unspec_for_n_fp, mode);
 	    break;
 
 	  default:
 	    gcc_unreachable ();
 	  }
-	return e.use_cond_insn (code, 0);
+	return e.use_exact_insn (code);
 
+      case PRED_m:
       case PRED_x:
 	switch (e.mode_suffix_id)
 	  {
 	  case MODE_none:
-	    /* No suffix, "x" predicate.  */
+	    /* No suffix, "m" or "x" predicate.  */
 	    if (e.type_suffix (0).integer_p)
 	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
+		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, mode);
 	      else
-		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
+		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, mode);
 	    else
-	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, e.vector_mode (0));
+	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, mode);
 	    break;
 
 	  case MODE_n:
-	    /* _n suffix, "x" predicate.  */
+	    /* _n suffix, "m" or "x" predicate.  */
 	    if (e.type_suffix (0).integer_p)
 	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, e.vector_mode (0));
+		code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, mode);
 	      else
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, e.vector_mode (0));
+		code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, mode);
 	    else
-	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, e.vector_mode (0));
+	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, mode);
 	    break;
 
 	  default:
 	    gcc_unreachable ();
 	  }
-	return e.use_pred_x_insn (code);
+
+	if (e.pred == PRED_m)
+	  return e.use_cond_insn (code, 0);
+	else
+	  return e.use_pred_x_insn (code);
+	break;
 
       default:
 	gcc_unreachable ();
       }
+}
 
-    gcc_unreachable ();
+/* Map the function directly to CODE (UNSPEC, M) where M is the vector
+   mode associated with type suffix 0, except when there is no
+   predicate and no _n suffix, in which case we use the appropriate
+   rtx_code.  This is useful when the basic operation is mapped to a
+   standard RTX code and all other versions use different unspecs.  */
+class unspec_based_mve_function_exact_insn : public unspec_based_mve_function_base
+{
+public:
+  CONSTEXPR unspec_based_mve_function_exact_insn (rtx_code code_for_sint,
+						  rtx_code code_for_uint,
+						  rtx_code code_for_fp,
+						  int unspec_for_n_sint,
+						  int unspec_for_n_uint,
+						  int unspec_for_n_fp,
+						  int unspec_for_m_sint,
+						  int unspec_for_m_uint,
+						  int unspec_for_m_fp,
+						  int unspec_for_m_n_sint,
+						  int unspec_for_m_n_uint,
+						  int unspec_for_m_n_fp)
+    : unspec_based_mve_function_base (code_for_sint,
+				      code_for_uint,
+				      code_for_fp,
+				      -1,
+				      -1,
+				      -1,
+				      unspec_for_n_sint,
+				      unspec_for_n_uint,
+				      unspec_for_n_fp,
+				      unspec_for_m_sint,
+				      unspec_for_m_uint,
+				      unspec_for_m_fp,
+				      unspec_for_m_n_sint,
+				      unspec_for_m_n_uint,
+				      unspec_for_m_n_fp)
+  {}
+
+  rtx
+  expand (function_expander &e) const override
+  {
+    /* No suffix, no predicate, use the right RTX code.  */
+    if ((e.mode_suffix_id != MODE_n)
+	&& (e.pred == PRED_none))
+      return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint,
+				 m_code_for_fp);
+
+    return expand_unspec (e);
   }
 };
 
 /* Map the function directly to CODE (UNSPEC, M) where M is the vector
    mode associated with type suffix 0.  */
-class unspec_mve_function_exact_insn : public function_base
+class unspec_mve_function_exact_insn : public unspec_based_mve_function_base
 {
 public:
   CONSTEXPR unspec_mve_function_exact_insn (int unspec_for_sint,
@@ -242,143 +258,33 @@  public:
 					    int unspec_for_m_n_sint,
 					    int unspec_for_m_n_uint,
 					    int unspec_for_m_n_fp)
-    : m_unspec_for_sint (unspec_for_sint),
-      m_unspec_for_uint (unspec_for_uint),
-      m_unspec_for_fp (unspec_for_fp),
-      m_unspec_for_n_sint (unspec_for_n_sint),
-      m_unspec_for_n_uint (unspec_for_n_uint),
-      m_unspec_for_n_fp (unspec_for_n_fp),
-      m_unspec_for_m_sint (unspec_for_m_sint),
-      m_unspec_for_m_uint (unspec_for_m_uint),
-      m_unspec_for_m_fp (unspec_for_m_fp),
-      m_unspec_for_m_n_sint (unspec_for_m_n_sint),
-      m_unspec_for_m_n_uint (unspec_for_m_n_uint),
-      m_unspec_for_m_n_fp (unspec_for_m_n_fp)
+    : unspec_based_mve_function_base (UNKNOWN,
+				      UNKNOWN,
+				      UNKNOWN,
+				      unspec_for_sint,
+				      unspec_for_uint,
+				      unspec_for_fp,
+				      unspec_for_n_sint,
+				      unspec_for_n_uint,
+				      unspec_for_n_fp,
+				      unspec_for_m_sint,
+				      unspec_for_m_uint,
+				      unspec_for_m_fp,
+				      unspec_for_m_n_sint,
+				      unspec_for_m_n_uint,
+				      unspec_for_m_n_fp)
   {}
 
-  /* The unspec code associated with signed-integer, unsigned-integer
-     and floating-point operations respectively.  It covers the cases
-     with the _n suffix, and/or the _m predicate.  */
-  int m_unspec_for_sint;
-  int m_unspec_for_uint;
-  int m_unspec_for_fp;
-  int m_unspec_for_n_sint;
-  int m_unspec_for_n_uint;
-  int m_unspec_for_n_fp;
-  int m_unspec_for_m_sint;
-  int m_unspec_for_m_uint;
-  int m_unspec_for_m_fp;
-  int m_unspec_for_m_n_sint;
-  int m_unspec_for_m_n_uint;
-  int m_unspec_for_m_n_fp;
-
   rtx
   expand (function_expander &e) const override
   {
-    insn_code code;
-    switch (e.pred)
-      {
-      case PRED_none:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No predicate, no suffix.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_f (m_unspec_for_fp, e.vector_mode (0));
-	    break;
-
-	  case MODE_n:
-	    /* No predicate, _n suffix.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_n (m_unspec_for_n_uint, m_unspec_for_n_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_n (m_unspec_for_n_sint, m_unspec_for_n_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_n_f (m_unspec_for_n_fp, e.vector_mode (0));
-	    break;
-
-	  default:
-	    gcc_unreachable ();
-	  }
-	return e.use_exact_insn (code);
-
-      case PRED_m:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No suffix, "m" predicate.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, e.vector_mode (0));
-	    break;
-
-	  case MODE_n:
-	    /* _n suffix, "m" predicate.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, e.vector_mode (0));
-	    break;
-
-	  default:
-	    gcc_unreachable ();
-	  }
-	return e.use_cond_insn (code, 0);
-
-      case PRED_x:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No suffix, "x" predicate.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, e.vector_mode (0));
-	    break;
-
-	  case MODE_n:
-	    /* _n suffix, "x" predicate.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, e.vector_mode (0));
-	    break;
-
-	  default:
-	    gcc_unreachable ();
-	  }
-	return e.use_pred_x_insn (code);
-
-      default:
-	gcc_unreachable ();
-      }
-
-    gcc_unreachable ();
+    return expand_unspec (e);
   }
 };
 
 /* Map the function directly to CODE (UNSPEC), when there is a
    non-predicated version and one with the "_p" predicate.  */
-class unspec_mve_function_exact_insn_pred_p : public function_base
+class unspec_mve_function_exact_insn_pred_p : public unspec_based_mve_function_base
 {
 public:
   CONSTEXPR unspec_mve_function_exact_insn_pred_p (int unspec_for_sint,
@@ -387,19 +293,23 @@  public:
 						   int unspec_for_p_sint,
 						   int unspec_for_p_uint,
 						   int unspec_for_p_fp)
-    : m_unspec_for_sint (unspec_for_sint),
-      m_unspec_for_uint (unspec_for_uint),
-      m_unspec_for_fp (unspec_for_fp),
+    : unspec_based_mve_function_base (UNKNOWN, /* No RTX code.  */
+				      UNKNOWN,
+				      UNKNOWN,
+				      unspec_for_sint,
+				      unspec_for_uint,
+				      unspec_for_fp,
+				      -1, -1, -1, /* No _n intrinsics.  */
+				      -1, -1, -1, /* No _m intrinsics.  */
+				      -1, -1, -1), /* No _m_n intrinsics.  */
       m_unspec_for_p_sint (unspec_for_p_sint),
       m_unspec_for_p_uint (unspec_for_p_uint),
       m_unspec_for_p_fp (unspec_for_p_fp)
   {}
 
-  /* The unspec code associated with signed-integer and unsigned-integer
-     operations, with no predicate, or with "_p" predicate.  */
-  int m_unspec_for_sint;
-  int m_unspec_for_uint;
-  int m_unspec_for_fp;
+  /* The unspec code associated with signed-integer and
+     unsigned-integer or floating-point operations with "_p"
+     predicate.  */
   int m_unspec_for_p_sint;
   int m_unspec_for_p_uint;
   int m_unspec_for_p_fp;
@@ -440,45 +350,30 @@  public:
 	    gcc_unreachable ();
 	  }
       }
-    else
-      {
-	switch (e.pred)
-	  {
-	  case PRED_none:
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_f (m_unspec_for_fp, e.vector_mode (0));
-
-	    return e.use_exact_insn (code);
 
-	  case PRED_p:
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_p (m_unspec_for_p_uint, m_unspec_for_p_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_p (m_unspec_for_p_sint, m_unspec_for_p_sint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_p_f (m_unspec_for_p_fp, e.vector_mode (0));
+    if (e.pred == PRED_p)
+      {
+	machine_mode mode = e.vector_mode (0);
 
-	    return e.use_exact_insn (code);
+	if (e.type_suffix (0).integer_p)
+	  if (e.type_suffix (0).unsigned_p)
+	    code = code_for_mve_q_p (m_unspec_for_p_uint, m_unspec_for_p_uint, mode);
+	  else
+	    code = code_for_mve_q_p (m_unspec_for_p_sint, m_unspec_for_p_sint, mode);
+	else
+	  code = code_for_mve_q_p_f (m_unspec_for_p_fp, mode);
 
-	  default:
-	    gcc_unreachable ();
-	  }
+	return e.use_exact_insn (code);
       }
 
-    gcc_unreachable ();
+    return expand_unspec (e);
   }
 };
 
 /* Map the function directly to CODE (UNSPEC, M) for vshl-like
    builtins. The difference with unspec_mve_function_exact_insn is
    that this function handles MODE_r and the related unspecs..  */
-class unspec_mve_function_exact_insn_vshl : public function_base
+class unspec_mve_function_exact_insn_vshl : public unspec_based_mve_function_base
 {
 public:
   CONSTEXPR unspec_mve_function_exact_insn_vshl (int unspec_for_sint,
@@ -493,31 +388,29 @@  public:
 						 int unspec_for_m_r_uint,
 						 int unspec_for_r_sint,
 						 int unspec_for_r_uint)
-    : m_unspec_for_sint (unspec_for_sint),
-      m_unspec_for_uint (unspec_for_uint),
-      m_unspec_for_n_sint (unspec_for_n_sint),
-      m_unspec_for_n_uint (unspec_for_n_uint),
-      m_unspec_for_m_sint (unspec_for_m_sint),
-      m_unspec_for_m_uint (unspec_for_m_uint),
-      m_unspec_for_m_n_sint (unspec_for_m_n_sint),
-      m_unspec_for_m_n_uint (unspec_for_m_n_uint),
+    : unspec_based_mve_function_base (UNKNOWN,
+				      UNKNOWN,
+				      UNKNOWN,
+				      unspec_for_sint,
+				      unspec_for_uint,
+				      -1,
+				      unspec_for_n_sint,
+				      unspec_for_n_uint,
+				      -1,
+				      unspec_for_m_sint,
+				      unspec_for_m_uint,
+				      -1,
+				      unspec_for_m_n_sint,
+				      unspec_for_m_n_uint,
+				      -1),
       m_unspec_for_m_r_sint (unspec_for_m_r_sint),
       m_unspec_for_m_r_uint (unspec_for_m_r_uint),
       m_unspec_for_r_sint (unspec_for_r_sint),
       m_unspec_for_r_uint (unspec_for_r_uint)
   {}
 
-  /* The unspec code associated with signed-integer, unsigned-integer
-     and floating-point operations respectively.  It covers the cases
-     with the _n suffix, and/or the _m predicate.  */
-  int m_unspec_for_sint;
-  int m_unspec_for_uint;
-  int m_unspec_for_n_sint;
-  int m_unspec_for_n_uint;
-  int m_unspec_for_m_sint;
-  int m_unspec_for_m_uint;
-  int m_unspec_for_m_n_sint;
-  int m_unspec_for_m_n_uint;
+  /* The unspec code associated with signed-integer and unsigned-integer
+     operations with MODE_r with or without PRED_m.  */
   int m_unspec_for_m_r_sint;
   int m_unspec_for_m_r_uint;
   int m_unspec_for_r_sint;
@@ -527,101 +420,38 @@  public:
   expand (function_expander &e) const override
   {
     insn_code code;
-    switch (e.pred)
+    if (e.mode_suffix_id == MODE_r)
       {
-      case PRED_none:
-	switch (e.mode_suffix_id)
+	machine_mode mode = e.vector_mode (0);
+	switch (e.pred)
 	  {
-	  case MODE_none:
-	    /* No predicate, no suffix.  */
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
-	    break;
-
-	  case MODE_n:
-	    /* No predicate, _n suffix.  */
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_n (m_unspec_for_n_uint, m_unspec_for_n_uint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_n (m_unspec_for_n_sint, m_unspec_for_n_sint, e.vector_mode (0));
-	    break;
-
-	  case MODE_r:
+	  case PRED_none:
 	    /* No predicate, _r suffix.  */
 	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_r (m_unspec_for_r_uint, m_unspec_for_r_uint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_r (m_unspec_for_r_sint, m_unspec_for_r_sint, e.vector_mode (0));
-	    break;
-
-	  default:
-	    gcc_unreachable ();
-	  }
-	return e.use_exact_insn (code);
-
-      case PRED_m:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No suffix, "m" predicate.  */
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
-	    break;
-
-	  case MODE_n:
-	    /* _n suffix, "m" predicate.  */
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, e.vector_mode (0));
-	    else
-	      code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, e.vector_mode (0));
-	    break;
-
-	  case MODE_r:
-	    /* _r suffix, "m" predicate.  */
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_m_r (m_unspec_for_m_r_uint, m_unspec_for_m_r_uint, e.vector_mode (0));
+	      code = code_for_mve_q_r (m_unspec_for_r_uint, m_unspec_for_r_uint, mode);
 	    else
-	      code = code_for_mve_q_m_r (m_unspec_for_m_r_sint, m_unspec_for_m_r_sint, e.vector_mode (0));
-	    break;
-
-	  default:
-	    gcc_unreachable ();
-	  }
-	return e.use_cond_insn (code, 0);
+	      code = code_for_mve_q_r (m_unspec_for_r_sint, m_unspec_for_r_sint, mode);
+	    return e.use_exact_insn (code);
 
-      case PRED_x:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No suffix, "x" predicate.  */
+	  case PRED_m:
+	  case PRED_x:
+	    /* _r suffix, "m" or "x" predicate.  */
 	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
+	      code = code_for_mve_q_m_r (m_unspec_for_m_r_uint, m_unspec_for_m_r_uint, mode);
 	    else
-	      code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
-	    break;
+	      code = code_for_mve_q_m_r (m_unspec_for_m_r_sint, m_unspec_for_m_r_sint, mode);
 
-	  case MODE_n:
-	    /* _n suffix, "x" predicate.  */
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, e.vector_mode (0));
+	    if (e.pred == PRED_m)
+	      return e.use_cond_insn (code, 0);
 	    else
-	      code = code_for_mve_q_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, e.vector_mode (0));
-	    break;
+	      return e.use_pred_x_insn (code);
 
 	  default:
 	    gcc_unreachable ();
 	  }
-	return e.use_pred_x_insn (code);
-
-      default:
-	gcc_unreachable ();
       }
 
-    gcc_unreachable ();
+      return expand_unspec (e);
   }
 };
 
@@ -641,9 +471,8 @@  public:
     : unspec_based_mve_function_base (code_for_sint,
 				      code_for_uint,
 				      code_for_fp,
-				      -1,
-				      -1,
-				      -1,
+				      -1, -1, -1, /* No non-predicated, no mode intrinsics.  */
+				      -1, -1, -1, /* No _n intrinsics.  */
 				      unspec_for_m_sint,
 				      unspec_for_m_uint,
 				      unspec_for_m_fp,
@@ -738,7 +567,9 @@  public:
 /* Map the function directly to CODE (UNSPEC, UNSPEC, UNSPEC, M) where
    M is the vector mode associated with type suffix 0.  USed for the
    operations where there is a "rot90" or "rot270" suffix, depending
-   on the UNSPEC.  */
+   on the UNSPEC.  We cannot use
+   unspec_based_mve_function_base::expand_unspec () because we call
+   code_for_mve_q with one more parameter.  */
 class unspec_mve_function_exact_insn_rot : public function_base
 {
 public:
@@ -769,6 +600,7 @@  public:
   rtx
   expand (function_expander &e) const override
   {
+    machine_mode mode = e.vector_mode (0);
     insn_code code;
 
     switch (e.pred)
@@ -780,11 +612,11 @@  public:
 	    /* No predicate, no suffix.  */
 	    if (e.type_suffix (0).integer_p)
 	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0));
+		code = code_for_mve_q (m_unspec_for_uint, m_unspec_for_uint, m_unspec_for_uint, mode);
 	      else
-		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
+		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, m_unspec_for_sint, mode);
 	    else
-	      code = code_for_mve_q_f (m_unspec_for_fp, m_unspec_for_fp, e.vector_mode (0));
+	      code = code_for_mve_q_f (m_unspec_for_fp, m_unspec_for_fp, mode);
 	    break;
 
 	  default:
@@ -793,42 +625,28 @@  public:
 	return e.use_exact_insn (code);
 
       case PRED_m:
+      case PRED_x:
 	switch (e.mode_suffix_id)
 	  {
 	  case MODE_none:
-	    /* No suffix, "m" predicate.  */
+	    /* No suffix, "m" or "x" predicate.  */
 	    if (e.type_suffix (0).integer_p)
 	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
+		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, m_unspec_for_m_uint, mode);
 	      else
-		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
+		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, m_unspec_for_m_sint, mode);
 	    else
-	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, m_unspec_for_m_fp, e.vector_mode (0));
-	    break;
-
-	  default:
-	    gcc_unreachable ();
-	  }
-	return e.use_cond_insn (code, 0);
+	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, m_unspec_for_m_fp, mode);
 
-      case PRED_x:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No suffix, "x" predicate.  */
-	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_q_m (m_unspec_for_m_uint, m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
+	    if (e.pred == PRED_m)
+	      return e.use_cond_insn (code, 0);
 	    else
-	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, m_unspec_for_m_fp, e.vector_mode (0));
+	      return e.use_pred_x_insn (code);
 	    break;
 
 	  default:
 	    gcc_unreachable ();
 	  }
-	return e.use_pred_x_insn (code);
 
       default:
 	gcc_unreachable ();
@@ -866,6 +684,7 @@  public:
   rtx
   expand (function_expander &e) const override
   {
+    machine_mode mode = e.vector_mode (0);
     insn_code code;
 
     if (! e.type_suffix (0).integer_p)
@@ -879,29 +698,24 @@  public:
       case PRED_none:
 	/* No predicate, no suffix.  */
 	if (e.type_suffix (0).unsigned_p)
-	  code = code_for_mve_q_int (m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0));
+	  code = code_for_mve_q_int (m_unspec_for_uint, m_unspec_for_uint, mode);
 	else
-	  code = code_for_mve_q_int (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
+	  code = code_for_mve_q_int (m_unspec_for_sint, m_unspec_for_sint, mode);
 
 	return e.use_exact_insn (code);
 
       case PRED_m:
-	/* No suffix, "m" predicate.  */
-	if (e.type_suffix (0).unsigned_p)
-	  code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
-	else
-	  code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
-
-	return e.use_cond_insn (code, 0);
-
       case PRED_x:
-	/* No suffix, "x" predicate.  */
+	/* No suffix, "m" or "x" predicate.  */
 	if (e.type_suffix (0).unsigned_p)
-	  code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
+	  code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, mode);
 	else
-	  code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
+	  code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, mode);
 
-	return e.use_pred_x_insn (code);
+	if (e.pred == PRED_m)
+	  return e.use_cond_insn (code, 0);
+	else
+	  return e.use_pred_x_insn (code);
 
       default:
 	gcc_unreachable ();
@@ -933,6 +747,7 @@  public:
   rtx
   expand (function_expander &e) const override
   {
+    machine_mode mode = e.vector_mode (0);
     insn_code code;
 
     if (e.mode_suffix_id != MODE_none)
@@ -945,18 +760,18 @@  public:
       {
       case PRED_none:
 	/* No predicate, no suffix.  */
-	code = code_for_mve_q_poly (m_unspec_for_poly, m_unspec_for_poly, e.vector_mode (0));
+	code = code_for_mve_q_poly (m_unspec_for_poly, m_unspec_for_poly, mode);
 	return e.use_exact_insn (code);
 
       case PRED_m:
-	/* No suffix, "m" predicate.  */
-	code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, e.vector_mode (0));
-	return e.use_cond_insn (code, 0);
-
       case PRED_x:
-	/* No suffix, "x" predicate.  */
-	code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, e.vector_mode (0));
-	return e.use_pred_x_insn (code);
+	/* No suffix, "m" or "x" predicate.  */
+	code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, mode);
+
+	if (e.pred == PRED_m)
+	  return e.use_cond_insn (code, 0);
+	else
+	  return e.use_pred_x_insn (code);
 
       default:
 	gcc_unreachable ();