diff mbox series

[SVE,ACLE] Implement svlsl_wide

Message ID CAAgBjMkKv0keZd41Trjo87CUhrVV2DdAnxM+F+JQ8-zsSE=iZQ@mail.gmail.com
State New
Headers show
Series [SVE,ACLE] Implement svlsl_wide | expand

Commit Message

Prathamesh Kulkarni Jan. 18, 2019, 11:16 a.m. UTC
Hi,
I committed the attached patch to aarch64/sve-acle-branch that
implements svlsl_wide.

Thanks,
Prathamesh
diff mbox series

Patch

diff --git a/gcc/config/aarch64/aarch64-sve-builtins.c b/gcc/config/aarch64/aarch64-sve-builtins.c
index f080a67ef00..0e3db669422 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.c
+++ b/gcc/config/aarch64/aarch64-sve-builtins.c
@@ -123,7 +123,10 @@  enum function_shape {
 
      The final argument must be an integer constant expression in the
      range [1, <t0>_BITS].  */
-  SHAPE_shift_right_imm
+  SHAPE_shift_right_imm,
+
+  /* sv<t0>_t svfoo_wide[_t0](sv<t0>_t, svuint64_t).  */
+  SHAPE_binary_wide
 };
 
 /* Classifies an operation into "modes"; for example, to distinguish
@@ -169,6 +172,7 @@  enum function {
   FUNC_svdup,
   FUNC_sveor,
   FUNC_svindex,
+  FUNC_svlsl_wide,
   FUNC_svmax,
   FUNC_svmad,
   FUNC_svmin,
@@ -331,6 +335,7 @@  private:
   void sig_qq_0000 (const function_instance &, vec<tree> &);
   void sig_n_0000 (const function_instance &, vec<tree> &);
   void sig_qq_n_0000 (const function_instance &, vec<tree> &);
+  void sig_00i (const function_instance &, vec<tree> &);
   void sig_n_00i (const function_instance &, vec<tree> &);
 
   void apply_predication (const function_instance &, vec<tree> &);
@@ -371,6 +376,7 @@  public:
 private:
   tree resolve_uniform (unsigned int);
   tree resolve_dot ();
+  tree resolve_binary_wide ();
   tree resolve_uniform_imm (unsigned int, unsigned int);
 
   bool check_first_vector_argument (unsigned int, unsigned int &,
@@ -473,6 +479,7 @@  private:
   rtx expand_dup ();
   rtx expand_eor ();
   rtx expand_index ();
+  rtx expand_lsl_wide ();
   rtx expand_max ();
   rtx expand_min ();
   rtx expand_mad (unsigned int);
@@ -581,6 +588,12 @@  static const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = {
 #define TYPES_all_unsigned(S, D) \
   S (u8), S (u16), S (u32), S (u64)
 
+/* _s8 _s16 _s32
+   _u8 _u16 _u32.  */
+#define TYPES_all_bhsi(S, D) \
+  S (s8), S (s16), S (s32), \
+  S (u8), S (u16), S (u32)
+
 /* _s8 _s16 _s32 _s64
    _u8 _u16 _u32 _u64.  */
 #define TYPES_all_integer(S, D) \
@@ -625,6 +638,7 @@  DEF_SVE_TYPES_ARRAY (all_pred);
 DEF_SVE_TYPES_ARRAY (all_unsigned);
 DEF_SVE_TYPES_ARRAY (all_signed);
 DEF_SVE_TYPES_ARRAY (all_float);
+DEF_SVE_TYPES_ARRAY (all_bhsi);
 DEF_SVE_TYPES_ARRAY (all_integer);
 DEF_SVE_TYPES_ARRAY (all_data);
 DEF_SVE_TYPES_ARRAY (all_sdi_and_float);
@@ -891,6 +905,11 @@  arm_sve_h_builder::build (const function_group &group)
       add_overloaded_functions (group, MODE_n);
       build_all (&arm_sve_h_builder::sig_n_00i, group, MODE_n);
       break;
+
+    case SHAPE_binary_wide:
+      add_overloaded_functions (group, MODE_none);
+      build_all (&arm_sve_h_builder::sig_00i, group, MODE_none);
+      break;
     }
 }
 
@@ -1028,6 +1047,17 @@  arm_sve_h_builder::sig_qq_n_0000 (const function_instance &instance,
   types.quick_push (instance.quarter_scalar_type (0));
 }
 
+/* Describe the signature "sv<t0>_t svfoo[_t0](sv<t0>_t, svuint64_t)"
+   for INSTANCE in TYPES.  */
+void
+arm_sve_h_builder::sig_00i (const function_instance& instance,
+			    vec<tree> &types)
+{
+  for (unsigned i = 0; i < 2; ++i)
+    types.quick_push (instance.vector_type (0));
+  types.quick_push (acle_vector_types[VECTOR_TYPE_svuint64_t]);
+}
+
 /* Describe the signature "sv<t0>_t svfoo[_n_t0](sv<t0>_t, uint64_t)"
    for INSTANCE in TYPES.  */
 void
@@ -1190,6 +1220,7 @@  arm_sve_h_builder::get_attributes (const function_instance &instance)
     case FUNC_svdup:
     case FUNC_sveor:
     case FUNC_svindex:
+    case FUNC_svlsl_wide:
     case FUNC_svmax:
     case FUNC_svmad:
     case FUNC_svmin:
@@ -1246,6 +1277,7 @@  arm_sve_h_builder::get_explicit_types (function_shape shape)
     case SHAPE_ternary_opt_n:
     case SHAPE_ternary_qq_opt_n:
     case SHAPE_shift_right_imm:
+    case SHAPE_binary_wide:
       return 0;
     }
   gcc_unreachable ();
@@ -1325,6 +1357,8 @@  function_resolver::resolve ()
     case SHAPE_binary_scalar:
     case SHAPE_inherent:
       break;
+    case SHAPE_binary_wide:
+      return resolve_binary_wide ();
     }
   gcc_unreachable ();
 }
@@ -1385,6 +1419,22 @@  function_resolver::resolve_dot ()
   return require_form (m_rfn.instance.mode, get_type_suffix (type));
 }
 
+/* Resolve a function that has SHAPE_binary_wide.  */
+
+tree
+function_resolver::resolve_binary_wide ()
+{
+  unsigned i, nargs;
+  vector_type type;
+
+  if (!check_first_vector_argument (2, i, nargs, type)
+      || !require_matching_type (i, type)
+      || !check_argument (i + 1, VECTOR_TYPE_svuint64_t))
+    return error_mark_node;
+
+  return require_form (m_rfn.instance.mode, get_type_suffix (type));
+}
+
 /* Like resolve_uniform, except that the final NIMM arguments have
    type uint64_t and must be integer constant expressions.  */
 tree
@@ -1653,6 +1703,7 @@  function_checker::check ()
     case SHAPE_binary_scalar:
     case SHAPE_ternary_opt_n:
     case SHAPE_ternary_qq_opt_n:
+    case SHAPE_binary_wide:
       return true;
     }
   gcc_unreachable ();
@@ -1842,6 +1893,7 @@  gimple_folder::fold ()
     case FUNC_svdup:
     case FUNC_sveor:
     case FUNC_svindex:
+    case FUNC_svlsl_wide:
     case FUNC_svmax:
     case FUNC_svmad:
     case FUNC_svmin:
@@ -1947,6 +1999,9 @@  function_expander::expand ()
     case FUNC_svindex:
       return expand_index ();
 
+    case FUNC_svlsl_wide:
+      return expand_lsl_wide ();
+
     case FUNC_svmax:
       return expand_max ();
 
@@ -2114,6 +2169,24 @@  function_expander::expand_index ()
   return expand_via_unpred_direct_optab (vec_series_optab);
 }
 
+/* Expand a call to svlsl_wide.  */
+rtx
+function_expander::expand_lsl_wide ()
+{
+  machine_mode mode = get_mode (0);
+
+  if (m_fi.pred == PRED_x)
+    {
+      insn_code icode = code_for_aarch64_pred (UNSPEC_ASHIFT_WIDE, mode);
+      return expand_via_pred_x_insn (icode);
+    }
+  else
+    {
+      insn_code icode = code_for_cond (UNSPEC_ASHIFT_WIDE, mode);
+      return expand_via_pred_insn (icode);
+    }
+}
+
 /* Expand a call to svmax.  */
 rtx
 function_expander::expand_max ()
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.def b/gcc/config/aarch64/aarch64-sve-builtins.def
index 0977d4a2de6..7981261a295 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.def
+++ b/gcc/config/aarch64/aarch64-sve-builtins.def
@@ -71,6 +71,7 @@  DEF_SVE_FUNCTION (svdot, ternary_qq_opt_n, sdi, none)
 DEF_SVE_FUNCTION (svdup, unary_n, all_data, mxznone)
 DEF_SVE_FUNCTION (sveor, binary_opt_n, all_integer, mxz)
 DEF_SVE_FUNCTION (svindex, binary_scalar, all_data, none)
+DEF_SVE_FUNCTION (svlsl_wide, binary_wide, all_bhsi, mxz)
 DEF_SVE_FUNCTION (svmax, binary_opt_n, all_data, mxz)
 DEF_SVE_FUNCTION (svmin, binary_opt_n, all_data, mxz)
 DEF_SVE_FUNCTION (svmad, ternary_opt_n, all_data, mxz)
diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md
index cbf9a7fb0bf..d48028931f3 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -1549,6 +1549,65 @@ 
   }
 )
 
+(define_insn "@aarch64_pred_<sve_int_op><mode>"
+  [(set (match_operand:SVE_BHSI 0 "register_operand" "=w, ?&w")
+        (unspec:SVE_BHSI
+	  [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl")
+	  (unspec:SVE_BHSI
+	    [(match_operand:SVE_BHSI 2 "register_operand" "0, w")
+	     (match_operand:VNx2DI 3 "register_operand" "w, w")]
+	    SVE_ASHIFT_WIDE)]
+	  UNSPEC_MERGE_PTRUE))]
+  "TARGET_SVE"
+  "@
+   <sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d
+   movprfx\t%0, %2\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d"
+  [(set_attr "movprfx" "*,yes")]
+)
+
+(define_expand "@cond_<sve_int_op><mode>"
+  [(set (match_operand:SVE_BHSI 0 "register_operand")
+	(unspec:SVE_BHSI
+	  [(match_operand:<VPRED> 1 "register_operand")
+	   (unspec:SVE_BHSI
+	     [(match_operand:SVE_BHSI 2 "register_operand")
+	      (match_operand:VNx2DI 3 "register_operand")]
+	     SVE_ASHIFT_WIDE)
+	   (match_operand:SVE_BHSI 4 "aarch64_simd_reg_or_zero")]
+	  UNSPEC_SEL))]
+  "TARGET_SVE"
+)
+
+(define_insn "*cond<sve_int_op><mode>_m"
+  [(set (match_operand:SVE_BHSI 0 "register_operand" "=w, ?&w")
+	(unspec:SVE_BHSI
+	  [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl")
+	   (unspec:SVE_BHSI
+	     [(match_operand:SVE_BHSI 2 "register_operand" "0, w")
+	      (match_operand:VNx2DI 3 "register_operand" "w, w")]
+	     SVE_ASHIFT_WIDE)
+	   (match_dup 2)]
+	 UNSPEC_SEL))]
+  "TARGET_SVE"
+  "@
+   <sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d
+   movprfx\t%0, %2\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d"
+  [(set_attr "movprfx" "*, yes")])
+
+(define_insn "*cond<sve_int_op><mode>_z"
+  [(set (match_operand:SVE_BHSI 0 "register_operand" "=&w")
+        (unspec:SVE_BHSI
+          [(match_operand:<VPRED> 1 "register_operand" "Upl")
+           (unspec:SVE_BHSI
+             [(match_operand:SVE_BHSI 2 "register_operand" "0w")
+              (match_operand:VNx2DI 3 "register_operand" "w")]
+             SVE_ASHIFT_WIDE)
+           (match_operand:SVE_BHSI 4 "aarch64_simd_imm_zero")]
+         UNSPEC_SEL))]
+  "TARGET_SVE"
+  "movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;<sve_int_op>\t%0.<Vetype>, %1/m, %0.<Vetype>, %3.d"
+  [(set_attr "movprfx" "yes")])
+
 ;; Test all bits of operand 1.  Operand 0 is a GP that is known to hold PTRUE.
 ;;
 ;; Using UNSPEC_PTEST_PTRUE allows combine patterns to assume that the GP
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 14d6811310a..5baa9d53448 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -490,6 +490,7 @@ 
     UNSPEC_COND_GE	; Used in aarch64-sve.md.
     UNSPEC_COND_GT	; Used in aarch64-sve.md.
     UNSPEC_LASTB	; Used in aarch64-sve.md.
+    UNSPEC_ASHIFT_WIDE  ; Used in aarch64-sve.md.
 ])
 
 ;; ------------------------------------------------------------------
@@ -1616,6 +1617,8 @@ 
  [(UNSPECV_ATOMIC_LDOP_OR "set") (UNSPECV_ATOMIC_LDOP_BIC "clr")
   (UNSPECV_ATOMIC_LDOP_XOR "eor") (UNSPECV_ATOMIC_LDOP_PLUS "add")])
 
+(define_int_iterator SVE_ASHIFT_WIDE [UNSPEC_ASHIFT_WIDE])
+
 ;; -------------------------------------------------------------------
 ;; Int Iterators Attributes.
 ;; -------------------------------------------------------------------
@@ -1880,6 +1883,8 @@ 
 			 (UNSPEC_COND_GE "ge")
 			 (UNSPEC_COND_GT "gt")])
 
+(define_int_attr sve_int_op [(UNSPEC_ASHIFT_WIDE "lsl")])
+
 (define_int_attr sve_fp_op [(UNSPEC_COND_MUL "fmul")
 			    (UNSPEC_COND_DIV "fdiv")
 			    (UNSPEC_COND_FABS "fabs")
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 7eeec767445..e9d5dbe4fd1 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -1996,6 +1996,7 @@  process_alt_operands (int only_alternative)
       if (!TEST_BIT (preferred, nalt))
 	continue;
 
+      bool matching_early_clobber[MAX_RECOG_OPERANDS];
       curr_small_class_check++;
       overall = losers = addr_losers = 0;
       static_reject = reject = reload_nregs = reload_sum = 0;
@@ -2007,6 +2008,7 @@  process_alt_operands (int only_alternative)
 	    fprintf (lra_dump_file,
 		     "            Staticly defined alt reject+=%d\n", inc);
 	  static_reject += inc;
+	  matching_early_clobber[nop] = 0;
 	}
       reject += static_reject;
       early_clobbered_regs_num = 0;
@@ -2202,7 +2204,11 @@  process_alt_operands (int only_alternative)
 				 "            %d Matching earlyclobber alt:"
 				 " reject--\n",
 				 nop);
-			    reject--;
+			    if (!matching_early_clobber[m])
+			      {
+				reject--;
+				matching_early_clobber[m] = 1;
+			      }
 			  }
 			/* Otherwise we prefer no matching
 			   alternatives because it gives more freedom
@@ -2948,15 +2954,11 @@  process_alt_operands (int only_alternative)
 	      curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++]
 		= last_conflict_j;
 	      losers++;
-	      /* Early clobber was already reflected in REJECT. */
-	      lra_assert (reject > 0);
 	      if (lra_dump_file != NULL)
 		fprintf
 		  (lra_dump_file,
 		   "            %d Conflict early clobber reload: reject--\n",
 		   i);
-	      reject--;
-	      overall += LRA_LOSER_COST_FACTOR - 1;
 	    }
 	  else
 	    {
@@ -2980,17 +2982,21 @@  process_alt_operands (int only_alternative)
 		}
 	      curr_alt_win[i] = curr_alt_match_win[i] = false;
 	      losers++;
-	      /* Early clobber was already reflected in REJECT. */
-	      lra_assert (reject > 0);
 	      if (lra_dump_file != NULL)
 		fprintf
 		  (lra_dump_file,
 		   "            %d Matched conflict early clobber reloads: "
 		   "reject--\n",
 		   i);
+	    }
+	  /* Early clobber was already reflected in REJECT. */
+	  if (!matching_early_clobber[i])
+	    {
+	      lra_assert (reject > 0);
 	      reject--;
-	      overall += LRA_LOSER_COST_FACTOR - 1;
+	      matching_early_clobber[i] = 1;
 	    }
+	  overall += LRA_LOSER_COST_FACTOR - 1;
 	}
       if (lra_dump_file != NULL)
 	fprintf (lra_dump_file, "          alt=%d,overall=%d,losers=%d,rld_nregs=%d\n",
diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/lsl_wide_1.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/lsl_wide_1.C
new file mode 100644
index 00000000000..e0084678fb3
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/lsl_wide_1.C
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h"
+
+svuint8_t
+f1 (svbool_t pg, svuint8_t x, svint8_t w, svuint64_t y)
+{
+  svlsl_wide_u8_x (pg, x, x); /* { dg-error "cannot convert 'svuint8_t' to 'svuint64_t'" } */
+  svlsl_wide_u8_x (pg, x); /* { dg-error {too few arguments to function 'svuint8_t svlsl_wide_u8_x\(svbool_t, svuint8_t, svuint64_t\)'} } */
+  svlsl_wide_u8_x (pg, x, y, x); /* { dg-error {too many arguments to function 'svuint8_t svlsl_wide_u8_x\(svbool_t, svuint8_t, svuint64_t\)'} } */
+  return svlsl_wide_s8_x (pg, w, y); /* { dg-error {cannot convert 'svint8_t' to 'svuint8_t' in return} } */
+}
diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/lsl_wide_2.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/lsl_wide_2.C
new file mode 100644
index 00000000000..8df049b6558
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/lsl_wide_2.C
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h"
+
+void
+f1 (svbool_t pg, svuint8_t x, svuint64_t y)
+{
+  svlsl_wide_x (pg, x); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint8_t&\)'} } */
+  svlsl_wide_x (pg, x, x, x, x); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint8_t&, svuint8_t&, svuint8_t&, svuint8_t&\)'} } */ 
+  svlsl_wide_x (x, x, y); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svuint8_t&, svuint8_t&, svuint64_t&\)'} } */ 
+  svlsl_wide_x (pg, 1, y); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, int, svuint64_t&\)'} } */
+  svlsl_wide_x (pg, x, x); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint8_t&, svuint8_t&\)'} } */
+  svlsl_wide_x (pg, y, y); /* { dg-error {no matching function for call to 'svlsl_wide_x\(svbool_t&, svuint64_t&, svuint64_t&\)'} } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s16.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s16.c
new file mode 100644
index 00000000000..328b5973c2f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s16.c
@@ -0,0 +1,77 @@ 
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** lsl_wide_s16_m_tied1:
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s16_m_tied1, svint16_t,
+	     z0 = svlsl_wide_s16_m (p0, z0, z16),
+	     z0 = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_s16_m_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s16_m_untied, svint16_t,
+	     z0 = svlsl_wide_s16_m (p0, z1, z16),
+	     z0 = svlsl_wide_m (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s16_m_tied2, svint16_t,
+	     z16_res = svlsl_wide_s16_m (p0, z0, z16),
+	     z16_res = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_s16_z_tied1:
+**	movprfx	z0\.h, p0/z, z0\.h
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s16_z_tied1, svint16_t,
+	     z0 = svlsl_wide_s16_z (p0, z0, z16),
+	     z0 = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_s16_z_untied:
+**	movprfx	z0\.h, p0/z, z1\.h
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s16_z_untied, svint16_t,
+	     z0 = svlsl_wide_s16_z (p0, z1, z16),
+	     z0 = svlsl_wide_z (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s16_z_tied2, svint16_t,
+	     z16_res = svlsl_wide_s16_z (p0, z0, z16),
+	     z16_res = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_s16_x_tied1:
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s16_x_tied1, svint16_t,
+	     z0 = svlsl_wide_s16_x (p0, z0, z16),
+	     z0 = svlsl_wide_x (p0, z0, z16))
+
+/*
+** lsl_wide_s16_x_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s16_x_untied, svint16_t,
+	     z0 = svlsl_wide_s16_x (p0, z1, z16),
+	     z0 = svlsl_wide_x (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s16_x_tied2, svint16_t,
+	     z16_res = svlsl_wide_s16_x (p0, z0, z16),
+	     z16_res = svlsl_wide_x (p0, z0, z16))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s32.c
new file mode 100644
index 00000000000..304b740f015
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s32.c
@@ -0,0 +1,77 @@ 
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** lsl_wide_s32_m_tied1:
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s32_m_tied1, svint32_t,
+	     z0 = svlsl_wide_s32_m (p0, z0, z16),
+	     z0 = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_s32_m_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s32_m_untied, svint32_t,
+	     z0 = svlsl_wide_s32_m (p0, z1, z16),
+	     z0 = svlsl_wide_m (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s32_m_tied2, svint32_t,
+	     z16_res = svlsl_wide_s32_m (p0, z0, z16),
+	     z16_res = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_s32_z_tied1:
+**	movprfx	z0\.s, p0/z, z0\.s
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s32_z_tied1, svint32_t,
+	     z0 = svlsl_wide_s32_z (p0, z0, z16),
+	     z0 = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_s32_z_untied:
+**	movprfx	z0\.s, p0/z, z1\.s
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s32_z_untied, svint32_t,
+	     z0 = svlsl_wide_s32_z (p0, z1, z16),
+	     z0 = svlsl_wide_z (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s32_z_tied2, svint32_t,
+	     z16_res = svlsl_wide_s32_z (p0, z0, z16),
+	     z16_res = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_s32_x_tied1:
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s32_x_tied1, svint32_t,
+	     z0 = svlsl_wide_s32_x (p0, z0, z16),
+	     z0 = svlsl_wide_x (p0, z0, z16))
+
+/*
+** lsl_wide_s32_x_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s32_x_untied, svint32_t,
+	     z0 = svlsl_wide_s32_x (p0, z1, z16),
+	     z0 = svlsl_wide_x (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s32_x_tied2, svint32_t,
+	     z16_res = svlsl_wide_s32_x (p0, z0, z16),
+	     z16_res = svlsl_wide_x (p0, z0, z16))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s8.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s8.c
new file mode 100644
index 00000000000..094ab154c34
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_s8.c
@@ -0,0 +1,77 @@ 
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** lsl_wide_s8_m_tied1:
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s8_m_tied1, svint8_t,
+	     z0 = svlsl_wide_s8_m (p0, z0, z16),
+	     z0 = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_s8_m_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s8_m_untied, svint8_t,
+	     z0 = svlsl_wide_s8_m (p0, z1, z16),
+	     z0 = svlsl_wide_m (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s8_m_tied2, svint8_t,
+	     z16_res = svlsl_wide_s8_m (p0, z0, z16),
+	     z16_res = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_s8_z_tied1:
+**	movprfx	z0\.b, p0/z, z0\.b
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s8_z_tied1, svint8_t,
+	     z0 = svlsl_wide_s8_z (p0, z0, z16),
+	     z0 = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_s8_z_untied:
+**	movprfx	z0\.b, p0/z, z1\.b
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s8_z_untied, svint8_t,
+	     z0 = svlsl_wide_s8_z (p0, z1, z16),
+	     z0 = svlsl_wide_z (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s8_z_tied2, svint8_t,
+	     z16_res = svlsl_wide_s8_z (p0, z0, z16),
+	     z16_res = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_s8_x_tied1:
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s8_x_tied1, svint8_t,
+	     z0 = svlsl_wide_s8_x (p0, z0, z16),
+	     z0 = svlsl_wide_x (p0, z0, z16))
+
+/*
+** lsl_wide_s8_x_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_s8_x_untied, svint8_t,
+	     z0 = svlsl_wide_s8_x (p0, z1, z16),
+	     z0 = svlsl_wide_x (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_s8_x_tied2, svint8_t,
+	     z16_res = svlsl_wide_s8_x (p0, z0, z16),
+	     z16_res = svlsl_wide_x (p0, z0, z16))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u16.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u16.c
new file mode 100644
index 00000000000..4f4ac169d74
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u16.c
@@ -0,0 +1,77 @@ 
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** lsl_wide_u16_m_tied1:
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u16_m_tied1, svuint16_t,
+	     z0 = svlsl_wide_u16_m (p0, z0, z16),
+	     z0 = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_u16_m_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u16_m_untied, svuint16_t,
+	     z0 = svlsl_wide_u16_m (p0, z1, z16),
+	     z0 = svlsl_wide_m (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u16_m_tied2, svuint16_t,
+	     z16_res = svlsl_wide_u16_m (p0, z0, z16),
+	     z16_res = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_u16_z_tied1:
+**	movprfx	z0\.h, p0/z, z0\.h
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u16_z_tied1, svuint16_t,
+	     z0 = svlsl_wide_u16_z (p0, z0, z16),
+	     z0 = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_u16_z_untied:
+**	movprfx	z0\.h, p0/z, z1\.h
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u16_z_untied, svuint16_t,
+	     z0 = svlsl_wide_u16_z (p0, z1, z16),
+	     z0 = svlsl_wide_z (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u16_z_tied2, svuint16_t,
+	     z16_res = svlsl_wide_u16_z (p0, z0, z16),
+	     z16_res = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_u16_x_tied1:
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u16_x_tied1, svuint16_t,
+	     z0 = svlsl_wide_u16_x (p0, z0, z16),
+	     z0 = svlsl_wide_x (p0, z0, z16))
+
+/*
+** lsl_wide_u16_x_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.h, p0/m, z0\.h, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u16_x_untied, svuint16_t,
+	     z0 = svlsl_wide_u16_x (p0, z1, z16),
+	     z0 = svlsl_wide_x (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u16_x_tied2, svuint16_t,
+	     z16_res = svlsl_wide_u16_x (p0, z0, z16),
+	     z16_res = svlsl_wide_x (p0, z0, z16))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u32.c
new file mode 100644
index 00000000000..163abc8862d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u32.c
@@ -0,0 +1,77 @@ 
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** lsl_wide_u32_m_tied1:
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u32_m_tied1, svuint32_t,
+	     z0 = svlsl_wide_u32_m (p0, z0, z16),
+	     z0 = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_u32_m_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u32_m_untied, svuint32_t,
+	     z0 = svlsl_wide_u32_m (p0, z1, z16),
+	     z0 = svlsl_wide_m (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u32_m_tied2, svuint32_t,
+	     z16_res = svlsl_wide_u32_m (p0, z0, z16),
+	     z16_res = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_u32_z_tied1:
+**	movprfx	z0\.s, p0/z, z0\.s
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u32_z_tied1, svuint32_t,
+	     z0 = svlsl_wide_u32_z (p0, z0, z16),
+	     z0 = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_u32_z_untied:
+**	movprfx	z0\.s, p0/z, z1\.s
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u32_z_untied, svuint32_t,
+	     z0 = svlsl_wide_u32_z (p0, z1, z16),
+	     z0 = svlsl_wide_z (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u32_z_tied2, svuint32_t,
+	     z16_res = svlsl_wide_u32_z (p0, z0, z16),
+	     z16_res = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_u32_x_tied1:
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u32_x_tied1, svuint32_t,
+	     z0 = svlsl_wide_u32_x (p0, z0, z16),
+	     z0 = svlsl_wide_x (p0, z0, z16))
+
+/*
+** lsl_wide_u32_x_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.s, p0/m, z0\.s, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u32_x_untied, svuint32_t,
+	     z0 = svlsl_wide_u32_x (p0, z1, z16),
+	     z0 = svlsl_wide_x (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u32_x_tied2, svuint32_t,
+	     z16_res = svlsl_wide_u32_x (p0, z0, z16),
+	     z16_res = svlsl_wide_x (p0, z0, z16))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u8.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u8.c
new file mode 100644
index 00000000000..505b8f3b04c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/lsl_wide_u8.c
@@ -0,0 +1,77 @@ 
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** lsl_wide_u8_m_tied1:
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u8_m_tied1, svuint8_t,
+	     z0 = svlsl_wide_u8_m (p0, z0, z16),
+	     z0 = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_u8_m_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u8_m_untied, svuint8_t,
+	     z0 = svlsl_wide_u8_m (p0, z1, z16),
+	     z0 = svlsl_wide_m (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u8_m_tied2, svuint8_t,
+	     z16_res = svlsl_wide_u8_m (p0, z0, z16),
+	     z16_res = svlsl_wide_m (p0, z0, z16))
+
+/*
+** lsl_wide_u8_z_tied1:
+**	movprfx	z0\.b, p0/z, z0\.b
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u8_z_tied1, svuint8_t,
+	     z0 = svlsl_wide_u8_z (p0, z0, z16),
+	     z0 = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_u8_z_untied:
+**	movprfx	z0\.b, p0/z, z1\.b
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u8_z_untied, svuint8_t,
+	     z0 = svlsl_wide_u8_z (p0, z1, z16),
+	     z0 = svlsl_wide_z (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u8_z_tied2, svuint8_t,
+	     z16_res = svlsl_wide_u8_z (p0, z0, z16),
+	     z16_res = svlsl_wide_z (p0, z0, z16))
+
+/*
+** lsl_wide_u8_x_tied1:
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u8_x_tied1, svuint8_t,
+	     z0 = svlsl_wide_u8_x (p0, z0, z16),
+	     z0 = svlsl_wide_x (p0, z0, z16))
+
+/*
+** lsl_wide_u8_x_untied:
+**	movprfx	z0, z1
+**	lsl	z0\.b, p0/m, z0\.b, z16\.d
+**	ret
+*/
+TEST_WIDE_Z (lsl_wide_u8_x_untied, svuint8_t,
+	     z0 = svlsl_wide_u8_x (p0, z1, z16),
+	     z0 = svlsl_wide_x (p0, z1, z16))
+
+/* Bad RA choice: no preferred output sequence.  */
+TEST_WIDE_Z (lsl_wide_u8_x_tied2, svuint8_t,
+	     z16_res = svlsl_wide_u8_x (p0, z0, z16),
+	     z16_res = svlsl_wide_x (p0, z0, z16))
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h
index 07b110c8ad5..888f8eacfd1 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h
@@ -120,6 +120,9 @@ 
     BIND_RESULT_ZS_FROM_Z16;				\
   }
 
+#define TEST_WIDE_Z(NAME, TYPE, CODE1, CODE2)		\
+  TEST_DUAL_Z (NAME, TYPE, svuint64_t, CODE1, CODE2)
+
 #define TEST_UNIFORM_ZS(NAME, ZTYPE, STYPE, CODE1, CODE2)	\
   START (NAME)							\
   {								\
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/lsl_wide_1.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/lsl_wide_1.c
new file mode 100644
index 00000000000..27d7581c6d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/lsl_wide_1.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h"
+
+svuint8_t
+f1 (svbool_t pg, svuint8_t x, svint8_t w, svuint64_t y)
+{
+  svlsl_wide_u8_x (pg, x, x); /* { dg-error "incompatible type for argument 3 of 'svlsl_wide_u8_x'" } */
+  svlsl_wide_u8_x (pg, x); /* { dg-error "too few arguments to function 'svlsl_wide_u8_x'" } */
+  svlsl_wide_u8_x (pg, x, y, x); /* { dg-error "too many arguments to function 'svlsl_wide_u8_x'" } */
+  return svlsl_wide_s8_x (pg, w, y); /* { dg-error "incompatible types when returning type 'svint8_t' but 'svuint8_t' was expected" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/lsl_wide_2.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/lsl_wide_2.c
new file mode 100644
index 00000000000..c0a609b1ca3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/lsl_wide_2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h"
+
+void
+f1 (svbool_t pg, svuint8_t x, svuint64_t y)
+{
+  svlsl_wide_x (pg, x); /* { dg-error "too few arguments to function 'svlsl_wide_x'" } */
+  svlsl_wide_x (pg, x, x, x, x); /* { dg-error "too many arguments to function 'svlsl_wide_x'" } */
+  svlsl_wide_x (x, x, y); /* { dg-error "passing 'svuint8_t' to argument 1 of 'svlsl_wide_x', which expects 'svbool_t'" } */
+  svlsl_wide_x (pg, 1, y); /* { dg-error "passing 'int' to argument 2 of 'svlsl_wide_x', which expects an SVE vector type" } */
+  svlsl_wide_x (pg, x, x); /* { dg-error "passing 'svuint8_t' to argument 3 of 'svlsl_wide_x', which expects 'svuint64_t'" } */
+  svlsl_wide_x (pg, y, y); /* { dg-error "'svlsl_wide_x' has no form that takes 'svuint64_t' arguments" } */
+}