diff mbox series

[v2,03/36] arm: [MVE intrinsics] Cleanup arm-mve-builtins-functions.h

Message ID 20240904132650.2720446-4-christophe.lyon@linaro.org
State New
Headers show
Series arm: [MVE intrinsics] Re-implement more intrinsics | expand

Commit Message

Christophe Lyon Sept. 4, 2024, 1:26 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 makes most of PRED_m and PRED_x handling use the same
code, and uses conditional operators when computing which RTX
code/unspec to use when calling code_for_mve_q_XXX.

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.  Use
	conditionals.
	(unspec_mve_function_exact_insn_vshl): Likewise.
	(unspec_based_mve_function_exact_insn_vcmp): Initialize new
	inherited members.  Use conditionals.
	(unspec_mve_function_exact_insn_rot): Merge PRED_m and PRED_x
	handling.  Use conditionals.
	(unspec_mve_function_exact_insn_vmull): Likewise.
	(unspec_mve_function_exact_insn_vmull_poly): Likewise.
---
 gcc/config/arm/arm-mve-builtins-functions.h | 726 ++++++++------------
 1 file changed, 286 insertions(+), 440 deletions(-)

Comments

Richard Earnshaw (lists) Oct. 14, 2024, 4:45 p.m. UTC | #1
On 04/09/2024 14:26, Christophe Lyon wrote:
> 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 makes most of PRED_m and PRED_x handling use the same
> code, and uses conditional operators when computing which RTX
> code/unspec to use when calling code_for_mve_q_XXX.
> 
> 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.  Use
> 	conditionals.
> 	(unspec_mve_function_exact_insn_vshl): Likewise.
> 	(unspec_based_mve_function_exact_insn_vcmp): Initialize new
> 	inherited members.  Use conditionals.
> 	(unspec_mve_function_exact_insn_rot): Merge PRED_m and PRED_x
> 	handling.  Use conditionals.
> 	(unspec_mve_function_exact_insn_vmull): Likewise.
> 	(unspec_mve_function_exact_insn_vmull_poly): Likewise.

OK.

R.

> ---
>  gcc/config/arm/arm-mve-builtins-functions.h | 726 ++++++++------------
>  1 file changed, 286 insertions(+), 440 deletions(-)
> 
> diff --git a/gcc/config/arm/arm-mve-builtins-functions.h b/gcc/config/arm/arm-mve-builtins-functions.h
> index ac2a731bff4..35cb5242b77 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,8 +104,101 @@ 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;
>  };
>  
> +/* 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
> +{
> +    machine_mode mode = e.vector_mode (0);
> +    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)
> +	      {
> +		int unspec = (e.type_suffix (0).unsigned_p
> +			      ? m_unspec_for_uint
> +			      : m_unspec_for_sint);
> +		code = code_for_mve_q (unspec, unspec, mode);
> +	      }
> +	    else
> +	      code = code_for_mve_q_f (m_unspec_for_fp, mode);
> +	    break;
> +
> +	  case MODE_n:
> +	    /* No predicate, _n suffix.  */
> +	    if (e.type_suffix (0).integer_p)
> +	      {
> +		int unspec = (e.type_suffix (0).unsigned_p
> +			      ? m_unspec_for_n_uint
> +			      : m_unspec_for_n_sint);
> +		code = code_for_mve_q_n (unspec, unspec, mode);
> +	      }
> +	    else
> +	      code = code_for_mve_q_n_f (m_unspec_for_n_fp, mode);
> +	    break;
> +
> +	  default:
> +	    gcc_unreachable ();
> +	  }
> +	return e.use_exact_insn (code);
> +
> +      case PRED_m:
> +      case PRED_x:
> +	switch (e.mode_suffix_id)
> +	  {
> +	  case MODE_none:
> +	    /* No suffix, "m" or "x" predicate.  */
> +	    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_m (unspec, unspec, mode);
> +	      }
> +	    else
> +	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, mode);
> +	    break;
> +
> +	  case MODE_n:
> +	    /* _n suffix, "m" or "x" predicate.  */
> +	    if (e.type_suffix (0).integer_p)
> +	      {
> +		int unspec = (e.type_suffix (0).unsigned_p
> +			      ? m_unspec_for_m_n_uint
> +			      : m_unspec_for_m_n_sint);
> +		code = code_for_mve_q_m_n (unspec, unspec, mode);
> +	      }
> +	    else
> +	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, mode);
> +	    break;
> +
> +	  default:
> +	    gcc_unreachable ();
> +	  }
> +
> +	if (e.pred == PRED_m)
> +	  return e.use_cond_insn (code, 0);
> +	else
> +	  return e.use_pred_x_insn (code);
> +	break;
> +
> +      default:
> +	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
> @@ -117,6 +222,9 @@ public:
>      : 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,
> @@ -137,97 +245,13 @@ public:
>        return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint,
>  				 m_code_for_fp);
>  
> -    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.  */
> -	    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, 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 +266,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 +301,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;
> @@ -408,6 +326,7 @@ public:
>    expand (function_expander &e) const override
>    {
>      insn_code code;
> +    int unspec;
>  
>      if (m_unspec_for_sint == VADDLVQ_S
>  	|| m_unspec_for_sint == VADDLVAQ_S
> @@ -423,62 +342,49 @@ public:
>  	switch (e.pred)
>  	  {
>  	  case PRED_none:
> -	    if (e.type_suffix (0).unsigned_p)
> -	      code = code_for_mve_q_v4si (m_unspec_for_uint, m_unspec_for_uint);
> -	    else
> -	      code = code_for_mve_q_v4si (m_unspec_for_sint, m_unspec_for_sint);
> +	    unspec = (e.type_suffix (0).unsigned_p
> +		      ? m_unspec_for_uint
> +		      : m_unspec_for_sint);
> +	    code = code_for_mve_q_v4si (unspec, unspec);
>  	    return e.use_exact_insn (code);
>  
>  	  case PRED_p:
> -	    if (e.type_suffix (0).unsigned_p)
> -	      code = code_for_mve_q_p_v4si (m_unspec_for_p_uint, m_unspec_for_p_uint);
> -	    else
> -	      code = code_for_mve_q_p_v4si (m_unspec_for_p_sint, m_unspec_for_p_sint);
> +	    unspec = (e.type_suffix (0).unsigned_p
> +		      ? m_unspec_for_p_uint
> +		      : m_unspec_for_p_sint);
> +	    code = code_for_mve_q_p_v4si (unspec, unspec);
>  	    return e.use_exact_insn (code);
>  
>  	  default:
>  	    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));
> -
> -	    return e.use_exact_insn (code);
> +    if (e.pred == PRED_p)
> +      {
> +	machine_mode mode = e.vector_mode (0);
>  
> -	  default:
> -	    gcc_unreachable ();
> +	if (e.type_suffix (0).integer_p)
> +	  {
> +	    unspec = (e.type_suffix (0).unsigned_p
> +		      ? m_unspec_for_p_uint
> +		      : m_unspec_for_p_sint);
> +	    code = code_for_mve_q_p (unspec, unspec, mode);
>  	  }
> +	else
> +	  code = code_for_mve_q_p_f (m_unspec_for_p_fp, mode);
> +
> +	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 +399,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 +431,40 @@ public:
>    expand (function_expander &e) const override
>    {
>      insn_code code;
> -    switch (e.pred)
> +    int unspec;
> +
> +    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));
> -	    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);
> -
> -      case PRED_x:
> -	switch (e.mode_suffix_id)
> -	  {
> -	  case MODE_none:
> -	    /* No suffix, "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));
> -	    else
> -	      code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
> -	    break;
> +	    unspec = (e.type_suffix (0).unsigned_p
> +		      ? m_unspec_for_r_uint
> +		      : m_unspec_for_r_sint);
> +	    code = code_for_mve_q_r (unspec, unspec, mode);
> +	    return e.use_exact_insn (code);
>  
> -	  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));
> +	  case PRED_m:
> +	  case PRED_x:
> +	    /* _r suffix, "m" or "x" predicate.  */
> +	    unspec = (e.type_suffix (0).unsigned_p
> +		      ? m_unspec_for_m_r_uint
> +		      : m_unspec_for_m_r_sint);
> +	    code = code_for_mve_q_m_r (unspec, unspec, mode);
> +
> +	    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 +484,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,
> @@ -662,24 +504,30 @@ public:
>      /* No suffix, no predicate, use the right RTX code.  */
>      if (e.pred == PRED_none)
>        {
> +	rtx_code r_code;
> +
>  	switch (e.mode_suffix_id)
>  	  {
>  	  case MODE_none:
>  	    if (e.type_suffix (0).integer_p)
> -	      if (e.type_suffix (0).unsigned_p)
> -		code = code_for_mve_vcmpq (m_code_for_uint, mode);
> -	      else
> -		code = code_for_mve_vcmpq (m_code_for_sint, mode);
> +	      {
> +		r_code = (e.type_suffix (0).unsigned_p
> +			  ? m_code_for_uint
> +			  : m_code_for_sint);
> +		code = code_for_mve_vcmpq (r_code, mode);
> +	      }
>  	    else
>  	      code = code_for_mve_vcmpq_f (m_code_for_fp, mode);
>  	    break;
>  
>  	  case MODE_n:
>  	    if (e.type_suffix (0).integer_p)
> -	      if (e.type_suffix (0).unsigned_p)
> -		code = code_for_mve_vcmpq_n (m_code_for_uint, mode);
> -	      else
> -		code = code_for_mve_vcmpq_n (m_code_for_sint, mode);
> +	      {
> +		r_code = (e.type_suffix (0).unsigned_p
> +			  ? m_code_for_uint
> +			  : m_code_for_sint);
> +		code = code_for_mve_vcmpq_n (r_code, mode);
> +	      }
>  	    else
>  	      code = code_for_mve_vcmpq_n_f (m_code_for_fp, mode);
>  	    break;
> @@ -691,6 +539,8 @@ public:
>        }
>      else
>        {
> +	int unspec;
> +
>  	switch (e.pred)
>  	  {
>  	  case PRED_m:
> @@ -699,10 +549,12 @@ public:
>  	      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_vcmpq_m (m_unspec_for_m_uint, m_unspec_for_m_uint, mode);
> -		  else
> -		    code = code_for_mve_vcmpq_m (m_unspec_for_m_sint, m_unspec_for_m_sint, mode);
> +		  {
> +		    unspec = (e.type_suffix (0).unsigned_p
> +			      ? m_unspec_for_m_uint
> +			      : m_unspec_for_m_sint);
> +		    code = code_for_mve_vcmpq_m (unspec, unspec, mode);
> +		  }
>  		else
>  		  code = code_for_mve_vcmpq_m_f (m_unspec_for_m_fp, mode);
>  		break;
> @@ -710,10 +562,12 @@ public:
>  	      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_vcmpq_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, mode);
> -		  else
> -		    code = code_for_mve_vcmpq_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, mode);
> +		  {
> +		    unspec = (e.type_suffix (0).unsigned_p
> +			      ? m_unspec_for_m_n_uint
> +			      : m_unspec_for_m_n_sint);
> +		    code = code_for_mve_vcmpq_m_n (unspec, unspec, mode);
> +		  }
>  		else
>  		  code = code_for_mve_vcmpq_m_n_f (m_unspec_for_m_n_fp, mode);
>  		break;
> @@ -738,7 +592,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,7 +625,9 @@ public:
>    rtx
>    expand (function_expander &e) const override
>    {
> +    machine_mode mode = e.vector_mode (0);
>      insn_code code;
> +    int unspec;
>  
>      switch (e.pred)
>        {
> @@ -779,12 +637,14 @@ public:
>  	  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, m_unspec_for_uint, e.vector_mode (0));
> -	      else
> -		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
> +	      {
> +		unspec = (e.type_suffix (0).unsigned_p
> +			  ? m_unspec_for_uint
> +			  : m_unspec_for_sint);
> +		code = code_for_mve_q (unspec, unspec, unspec, 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 +653,30 @@ 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));
> -	      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));
> +	      {
> +		unspec = (e.type_suffix (0).unsigned_p
> +			  ? m_unspec_for_m_uint
> +			  : m_unspec_for_m_sint);
> +		code = code_for_mve_q_m (unspec, unspec, unspec, 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,7 +714,9 @@ public:
>    rtx
>    expand (function_expander &e) const override
>    {
> +    machine_mode mode = e.vector_mode (0);
>      insn_code code;
> +    int unspec;
>  
>      if (! e.type_suffix (0).integer_p)
>        gcc_unreachable ();
> @@ -878,30 +728,25 @@ 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));
> -	else
> -	  code = code_for_mve_q_int (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
> +	unspec = (e.type_suffix (0).unsigned_p
> +		  ? m_unspec_for_uint
> +		  : m_unspec_for_sint);
> +	code = code_for_mve_q_int (unspec, unspec, 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.  */
> -	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));
> +	/* No suffix, "m" or "x" predicate.  */
> +	unspec = (e.type_suffix (0).unsigned_p
> +		  ? m_unspec_for_m_uint
> +		  : m_unspec_for_m_sint);
> +	code = code_for_mve_q_int_m (unspec, unspec, mode);
> +
> +	if (e.pred == PRED_m)
> +	  return e.use_cond_insn (code, 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_pred_x_insn (code);
> +	  return e.use_pred_x_insn (code);
>  
>        default:
>  	gcc_unreachable ();
> @@ -933,6 +778,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 +791,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 ();
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..35cb5242b77 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,8 +104,101 @@  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;
 };
 
+/* 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
+{
+    machine_mode mode = e.vector_mode (0);
+    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)
+	      {
+		int unspec = (e.type_suffix (0).unsigned_p
+			      ? m_unspec_for_uint
+			      : m_unspec_for_sint);
+		code = code_for_mve_q (unspec, unspec, mode);
+	      }
+	    else
+	      code = code_for_mve_q_f (m_unspec_for_fp, mode);
+	    break;
+
+	  case MODE_n:
+	    /* No predicate, _n suffix.  */
+	    if (e.type_suffix (0).integer_p)
+	      {
+		int unspec = (e.type_suffix (0).unsigned_p
+			      ? m_unspec_for_n_uint
+			      : m_unspec_for_n_sint);
+		code = code_for_mve_q_n (unspec, unspec, mode);
+	      }
+	    else
+	      code = code_for_mve_q_n_f (m_unspec_for_n_fp, mode);
+	    break;
+
+	  default:
+	    gcc_unreachable ();
+	  }
+	return e.use_exact_insn (code);
+
+      case PRED_m:
+      case PRED_x:
+	switch (e.mode_suffix_id)
+	  {
+	  case MODE_none:
+	    /* No suffix, "m" or "x" predicate.  */
+	    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_m (unspec, unspec, mode);
+	      }
+	    else
+	      code = code_for_mve_q_m_f (m_unspec_for_m_fp, mode);
+	    break;
+
+	  case MODE_n:
+	    /* _n suffix, "m" or "x" predicate.  */
+	    if (e.type_suffix (0).integer_p)
+	      {
+		int unspec = (e.type_suffix (0).unsigned_p
+			      ? m_unspec_for_m_n_uint
+			      : m_unspec_for_m_n_sint);
+		code = code_for_mve_q_m_n (unspec, unspec, mode);
+	      }
+	    else
+	      code = code_for_mve_q_m_n_f (m_unspec_for_m_n_fp, mode);
+	    break;
+
+	  default:
+	    gcc_unreachable ();
+	  }
+
+	if (e.pred == PRED_m)
+	  return e.use_cond_insn (code, 0);
+	else
+	  return e.use_pred_x_insn (code);
+	break;
+
+      default:
+	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
@@ -117,6 +222,9 @@  public:
     : 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,
@@ -137,97 +245,13 @@  public:
       return e.map_to_rtx_codes (m_code_for_sint, m_code_for_uint,
 				 m_code_for_fp);
 
-    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.  */
-	    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, 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 +266,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 +301,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;
@@ -408,6 +326,7 @@  public:
   expand (function_expander &e) const override
   {
     insn_code code;
+    int unspec;
 
     if (m_unspec_for_sint == VADDLVQ_S
 	|| m_unspec_for_sint == VADDLVAQ_S
@@ -423,62 +342,49 @@  public:
 	switch (e.pred)
 	  {
 	  case PRED_none:
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_v4si (m_unspec_for_uint, m_unspec_for_uint);
-	    else
-	      code = code_for_mve_q_v4si (m_unspec_for_sint, m_unspec_for_sint);
+	    unspec = (e.type_suffix (0).unsigned_p
+		      ? m_unspec_for_uint
+		      : m_unspec_for_sint);
+	    code = code_for_mve_q_v4si (unspec, unspec);
 	    return e.use_exact_insn (code);
 
 	  case PRED_p:
-	    if (e.type_suffix (0).unsigned_p)
-	      code = code_for_mve_q_p_v4si (m_unspec_for_p_uint, m_unspec_for_p_uint);
-	    else
-	      code = code_for_mve_q_p_v4si (m_unspec_for_p_sint, m_unspec_for_p_sint);
+	    unspec = (e.type_suffix (0).unsigned_p
+		      ? m_unspec_for_p_uint
+		      : m_unspec_for_p_sint);
+	    code = code_for_mve_q_p_v4si (unspec, unspec);
 	    return e.use_exact_insn (code);
 
 	  default:
 	    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));
-
-	    return e.use_exact_insn (code);
+    if (e.pred == PRED_p)
+      {
+	machine_mode mode = e.vector_mode (0);
 
-	  default:
-	    gcc_unreachable ();
+	if (e.type_suffix (0).integer_p)
+	  {
+	    unspec = (e.type_suffix (0).unsigned_p
+		      ? m_unspec_for_p_uint
+		      : m_unspec_for_p_sint);
+	    code = code_for_mve_q_p (unspec, unspec, mode);
 	  }
+	else
+	  code = code_for_mve_q_p_f (m_unspec_for_p_fp, mode);
+
+	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 +399,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 +431,40 @@  public:
   expand (function_expander &e) const override
   {
     insn_code code;
-    switch (e.pred)
+    int unspec;
+
+    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));
-	    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);
-
-      case PRED_x:
-	switch (e.mode_suffix_id)
-	  {
-	  case MODE_none:
-	    /* No suffix, "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));
-	    else
-	      code = code_for_mve_q_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
-	    break;
+	    unspec = (e.type_suffix (0).unsigned_p
+		      ? m_unspec_for_r_uint
+		      : m_unspec_for_r_sint);
+	    code = code_for_mve_q_r (unspec, unspec, mode);
+	    return e.use_exact_insn (code);
 
-	  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));
+	  case PRED_m:
+	  case PRED_x:
+	    /* _r suffix, "m" or "x" predicate.  */
+	    unspec = (e.type_suffix (0).unsigned_p
+		      ? m_unspec_for_m_r_uint
+		      : m_unspec_for_m_r_sint);
+	    code = code_for_mve_q_m_r (unspec, unspec, mode);
+
+	    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 +484,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,
@@ -662,24 +504,30 @@  public:
     /* No suffix, no predicate, use the right RTX code.  */
     if (e.pred == PRED_none)
       {
+	rtx_code r_code;
+
 	switch (e.mode_suffix_id)
 	  {
 	  case MODE_none:
 	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_vcmpq (m_code_for_uint, mode);
-	      else
-		code = code_for_mve_vcmpq (m_code_for_sint, mode);
+	      {
+		r_code = (e.type_suffix (0).unsigned_p
+			  ? m_code_for_uint
+			  : m_code_for_sint);
+		code = code_for_mve_vcmpq (r_code, mode);
+	      }
 	    else
 	      code = code_for_mve_vcmpq_f (m_code_for_fp, mode);
 	    break;
 
 	  case MODE_n:
 	    if (e.type_suffix (0).integer_p)
-	      if (e.type_suffix (0).unsigned_p)
-		code = code_for_mve_vcmpq_n (m_code_for_uint, mode);
-	      else
-		code = code_for_mve_vcmpq_n (m_code_for_sint, mode);
+	      {
+		r_code = (e.type_suffix (0).unsigned_p
+			  ? m_code_for_uint
+			  : m_code_for_sint);
+		code = code_for_mve_vcmpq_n (r_code, mode);
+	      }
 	    else
 	      code = code_for_mve_vcmpq_n_f (m_code_for_fp, mode);
 	    break;
@@ -691,6 +539,8 @@  public:
       }
     else
       {
+	int unspec;
+
 	switch (e.pred)
 	  {
 	  case PRED_m:
@@ -699,10 +549,12 @@  public:
 	      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_vcmpq_m (m_unspec_for_m_uint, m_unspec_for_m_uint, mode);
-		  else
-		    code = code_for_mve_vcmpq_m (m_unspec_for_m_sint, m_unspec_for_m_sint, mode);
+		  {
+		    unspec = (e.type_suffix (0).unsigned_p
+			      ? m_unspec_for_m_uint
+			      : m_unspec_for_m_sint);
+		    code = code_for_mve_vcmpq_m (unspec, unspec, mode);
+		  }
 		else
 		  code = code_for_mve_vcmpq_m_f (m_unspec_for_m_fp, mode);
 		break;
@@ -710,10 +562,12 @@  public:
 	      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_vcmpq_m_n (m_unspec_for_m_n_uint, m_unspec_for_m_n_uint, mode);
-		  else
-		    code = code_for_mve_vcmpq_m_n (m_unspec_for_m_n_sint, m_unspec_for_m_n_sint, mode);
+		  {
+		    unspec = (e.type_suffix (0).unsigned_p
+			      ? m_unspec_for_m_n_uint
+			      : m_unspec_for_m_n_sint);
+		    code = code_for_mve_vcmpq_m_n (unspec, unspec, mode);
+		  }
 		else
 		  code = code_for_mve_vcmpq_m_n_f (m_unspec_for_m_n_fp, mode);
 		break;
@@ -738,7 +592,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,7 +625,9 @@  public:
   rtx
   expand (function_expander &e) const override
   {
+    machine_mode mode = e.vector_mode (0);
     insn_code code;
+    int unspec;
 
     switch (e.pred)
       {
@@ -779,12 +637,14 @@  public:
 	  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, m_unspec_for_uint, e.vector_mode (0));
-	      else
-		code = code_for_mve_q (m_unspec_for_sint, m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
+	      {
+		unspec = (e.type_suffix (0).unsigned_p
+			  ? m_unspec_for_uint
+			  : m_unspec_for_sint);
+		code = code_for_mve_q (unspec, unspec, unspec, 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 +653,30 @@  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));
-	      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));
+	      {
+		unspec = (e.type_suffix (0).unsigned_p
+			  ? m_unspec_for_m_uint
+			  : m_unspec_for_m_sint);
+		code = code_for_mve_q_m (unspec, unspec, unspec, 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,7 +714,9 @@  public:
   rtx
   expand (function_expander &e) const override
   {
+    machine_mode mode = e.vector_mode (0);
     insn_code code;
+    int unspec;
 
     if (! e.type_suffix (0).integer_p)
       gcc_unreachable ();
@@ -878,30 +728,25 @@  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));
-	else
-	  code = code_for_mve_q_int (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
+	unspec = (e.type_suffix (0).unsigned_p
+		  ? m_unspec_for_uint
+		  : m_unspec_for_sint);
+	code = code_for_mve_q_int (unspec, unspec, 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.  */
-	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));
+	/* No suffix, "m" or "x" predicate.  */
+	unspec = (e.type_suffix (0).unsigned_p
+		  ? m_unspec_for_m_uint
+		  : m_unspec_for_m_sint);
+	code = code_for_mve_q_int_m (unspec, unspec, mode);
+
+	if (e.pred == PRED_m)
+	  return e.use_cond_insn (code, 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_pred_x_insn (code);
+	  return e.use_pred_x_insn (code);
 
       default:
 	gcc_unreachable ();
@@ -933,6 +778,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 +791,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 ();