From b75cd8ba8f911c137380677b85882c22a6467bf6 Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Fri, 18 Jan 2019 09:07:10 +1100
Subject: [PATCH] [SVE ACLE] Implements svdot

Change-Id: I9d9f77f814a62e03db2ccd749f41bd35fea16035
---
 gcc/config/aarch64/aarch64-sve-builtins.c          | 148 +++++++++++++++++++++
 gcc/config/aarch64/aarch64-sve-builtins.def        |   1 +
 gcc/config/aarch64/aarch64-sve.md                  |  14 ++
 gcc/config/aarch64/iterators.md                    |   6 +-
 .../aarch64/sve-acle/general-c++/dot_1.C           |   9 ++
 .../aarch64/sve-acle/general-c++/dot_2.C           |  17 +++
 .../gcc.target/aarch64/sve-acle/asm/dot_s32.c      | 111 ++++++++++++++++
 .../gcc.target/aarch64/sve-acle/asm/dot_s64.c      | 111 ++++++++++++++++
 .../gcc.target/aarch64/sve-acle/asm/dot_u32.c      | 111 ++++++++++++++++
 .../gcc.target/aarch64/sve-acle/asm/dot_u64.c      | 111 ++++++++++++++++
 .../aarch64/sve-acle/asm/test_sve_acle.h           |  48 +++++++
 .../gcc.target/aarch64/sve-acle/general-c/dot_1.c  |  13 ++
 .../gcc.target/aarch64/sve-acle/general-c/dot_2.c  |  15 +++
 13 files changed, 714 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c

diff --git a/gcc/config/aarch64/aarch64-sve-builtins.c b/gcc/config/aarch64/aarch64-sve-builtins.c
index 35ed531..f080a67 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.c
+++ b/gcc/config/aarch64/aarch64-sve-builtins.c
@@ -115,6 +115,10 @@ enum function_shape {
      sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0>_t, <t0>_t).  */
   SHAPE_ternary_opt_n,
 
+  /* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0.quarter>_t, sv<t0.quarter>_t)
+     sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0.quarter>_t, <t0.quarter>_t).  */
+  SHAPE_ternary_qq_opt_n,
+
   /* sv<t0>_t svfoo[_n_t0])(sv<t0>_t, uint64_t)
 
      The final argument must be an integer constant expression in the
@@ -161,6 +165,7 @@ enum function {
   FUNC_svasrd,
   FUNC_svdiv,
   FUNC_svdivr,
+  FUNC_svdot,
   FUNC_svdup,
   FUNC_sveor,
   FUNC_svindex,
@@ -261,6 +266,8 @@ struct GTY(()) function_instance {
 
   tree scalar_type (unsigned int) const;
   tree vector_type (unsigned int) const;
+  tree quarter_vector_type (unsigned int i) const;
+  tree quarter_scalar_type (unsigned int i) const;
 
   /* The explicit "enum"s are required for gengtype.  */
   enum group_id group;
@@ -321,7 +328,9 @@ private:
   void sig_000 (const function_instance &, vec<tree> &);
   void sig_n_000 (const function_instance &, vec<tree> &);
   void sig_0000 (const function_instance &, vec<tree> &);
+  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_n_00i (const function_instance &, vec<tree> &);
 
   void apply_predication (const function_instance &, vec<tree> &);
@@ -361,6 +370,7 @@ public:
 
 private:
   tree resolve_uniform (unsigned int);
+  tree resolve_dot ();
   tree resolve_uniform_imm (unsigned int, unsigned int);
 
   bool check_first_vector_argument (unsigned int, unsigned int &,
@@ -459,6 +469,7 @@ private:
   rtx expand_and ();
   rtx expand_asrd ();
   rtx expand_div (bool);
+  rtx expand_dot ();
   rtx expand_dup ();
   rtx expand_eor ();
   rtx expand_index ();
@@ -618,6 +629,7 @@ DEF_SVE_TYPES_ARRAY (all_integer);
 DEF_SVE_TYPES_ARRAY (all_data);
 DEF_SVE_TYPES_ARRAY (all_sdi_and_float);
 DEF_SVE_TYPES_ARRAY (all_signed_and_float);
+DEF_SVE_TYPES_ARRAY (sdi);
 
 /* Used by functions in aarch64-sve-builtins.def that have no governing
    predicate.  */
@@ -668,6 +680,43 @@ find_vector_type (const_tree type)
   return NUM_VECTOR_TYPES;
 }
 
+/* Return the type suffix associated with integer elements that have
+   ELEM_BITS bits and the signedness given by UNSIGNED_P.  Return
+   NUM_TYPE_SUFFIXES if no such element exists.  */
+static type_suffix
+maybe_find_integer_type_suffix (bool unsigned_p, unsigned int elem_bits)
+{
+  for (unsigned int i = 0; i < NUM_TYPE_SUFFIXES; ++i)
+    {
+      if (type_suffixes[i].integer_p
+	  && type_suffixes[i].unsigned_p == unsigned_p
+	  && type_suffixes[i].elem_bits == elem_bits)
+	return type_suffix (i);
+    }
+  return NUM_TYPE_SUFFIXES;
+}
+
+/* Return the type suffix for elements that are a quarter the size of integer
+   type suffix TYPE.  Return NUM_TYPE_SUFFIXES if no such element exists.  */
+static type_suffix
+maybe_find_quarter_type_suffix (type_suffix type)
+{
+  return maybe_find_integer_type_suffix (type_suffixes[type].unsigned_p,
+				   type_suffixes[type].elem_bits / 4);
+}
+
+/* Same as maybe_find_quarter_type_suffix but asserts if no such element
+   exists.  */
+static type_suffix
+find_quarter_type_suffix (type_suffix type)
+{
+  type_suffix ret
+    = maybe_find_integer_type_suffix (type_suffixes[type].unsigned_p,
+				      type_suffixes[type].elem_bits / 4);
+  gcc_assert (ret != NUM_TYPE_SUFFIXES);
+  return ret;
+}
+
 /* Report that LOCATION has a call to DECL in which argument ARGNO
    was not an integer constant expression.  */
 static void
@@ -742,6 +791,22 @@ function_instance::vector_type (unsigned int i) const
   return acle_vector_types[type_suffixes[types[i]].type];
 }
 
+/* Return the quarter size vector type associated with type suffix I.  */
+tree
+function_instance::quarter_vector_type (unsigned int i) const
+{
+  type_suffix quarter_type = find_quarter_type_suffix (types[i]);
+  return acle_vector_types[type_suffixes[quarter_type].type];
+}
+
+/* Return the quarter size scalar type associated with type suffix I.  */
+tree
+function_instance::quarter_scalar_type (unsigned int i) const
+{
+  type_suffix quarter_type = find_quarter_type_suffix (types[i]);
+  return scalar_types[type_suffixes[quarter_type].type];
+}
+
 inline hashval_t
 registered_function_hasher::hash (value_type value)
 {
@@ -811,6 +876,12 @@ arm_sve_h_builder::build (const function_group &group)
       build_all (&arm_sve_h_builder::sig_n_0000, group, MODE_n);
       break;
 
+    case SHAPE_ternary_qq_opt_n:
+      add_overloaded_functions (group, MODE_none);
+      build_all (&arm_sve_h_builder::sig_qq_0000, group, MODE_none);
+      build_all (&arm_sve_h_builder::sig_qq_n_0000, group, MODE_n);
+      break;
+
     case SHAPE_inherent:
       /* No overloaded functions here.  */
       build_all (&arm_sve_h_builder::sig_inherent, group, MODE_none);
@@ -908,6 +979,20 @@ arm_sve_h_builder::sig_0000 (const function_instance &instance,
     types.quick_push (instance.vector_type (0));
 }
 
+/* Describe the signature
+   "sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0.quarter>_t, sv<t0.quarter>_t)"
+   for INSTANCE in TYPES.  */
+void
+arm_sve_h_builder::sig_qq_0000 (const function_instance &instance,
+				vec<tree> &types)
+{
+  tree quarter_type = instance.quarter_vector_type (0);
+  types.quick_push (instance.vector_type (0));
+  types.quick_push (instance.vector_type (0));
+  types.quick_push (quarter_type);
+  types.quick_push (quarter_type);
+}
+
 /* Describe the signature "sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0>_t)"
    for INSTANCE in TYPES.  */
 void
@@ -930,6 +1015,19 @@ arm_sve_h_builder::sig_n_0000 (const function_instance &instance,
   types.quick_push (instance.scalar_type (0));
 }
 
+/* Describe the signature
+   "sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0.quarter>_t, <t0.quarter>_t)"
+   for INSTANCE in TYPES.  */
+void
+arm_sve_h_builder::sig_qq_n_0000 (const function_instance &instance,
+				  vec<tree> &types)
+{
+  for (unsigned int i = 0; i < 2; ++i)
+    types.quick_push (instance.vector_type (0));
+  types.quick_push (instance.quarter_vector_type (0));
+  types.quick_push (instance.quarter_scalar_type (0));
+}
+
 /* Describe the signature "sv<t0>_t svfoo[_n_t0](sv<t0>_t, uint64_t)"
    for INSTANCE in TYPES.  */
 void
@@ -1088,6 +1186,7 @@ arm_sve_h_builder::get_attributes (const function_instance &instance)
     case FUNC_svasrd:
     case FUNC_svdiv:
     case FUNC_svdivr:
+    case FUNC_svdot:
     case FUNC_svdup:
     case FUNC_sveor:
     case FUNC_svindex:
@@ -1145,6 +1244,7 @@ arm_sve_h_builder::get_explicit_types (function_shape shape)
     case SHAPE_unary:
     case SHAPE_binary_opt_n:
     case SHAPE_ternary_opt_n:
+    case SHAPE_ternary_qq_opt_n:
     case SHAPE_shift_right_imm:
       return 0;
     }
@@ -1218,6 +1318,8 @@ function_resolver::resolve ()
       return resolve_uniform (3);
     case SHAPE_shift_right_imm:
       return resolve_uniform_imm (2, 1);
+    case SHAPE_ternary_qq_opt_n:
+      return resolve_dot ();
     case SHAPE_unary_n:
       return NULL_TREE;
     case SHAPE_binary_scalar:
@@ -1252,6 +1354,37 @@ function_resolver::resolve_uniform (unsigned int nops)
   return require_form (m_rfn.instance.mode, get_type_suffix (type));
 }
 
+/* Resolve functions like svdot in which the elements of the result and
+   the first argument are four times wider than the elements of the other
+   arguments.  The final argument can be a vector or a scalar.  */
+tree
+function_resolver::resolve_dot ()
+{
+  /* Check that we have the right number of arguments.  */
+  unsigned int i, nargs;
+  vector_type type;
+
+  if (!check_first_vector_argument (3, i, nargs, type))
+    return error_mark_node;
+
+  /* Handle subsequent arguments.  */
+  type_suffix ts = maybe_find_quarter_type_suffix (get_type_suffix (type));
+  if (ts != NUM_TYPE_SUFFIXES)
+    {
+      vector_type arg_type = type_suffixes[ts].type;
+      if (!check_argument (1, arg_type))
+	return error_mark_node;
+
+      /* Allow the final argument to be scalar, if an _n form exists.  */
+      if (scalar_argument_p (2))
+	return require_n_form (get_type_suffix (type));
+      else if (!check_argument (2, arg_type))
+	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
@@ -1519,6 +1652,7 @@ function_checker::check ()
     case SHAPE_binary_opt_n:
     case SHAPE_binary_scalar:
     case SHAPE_ternary_opt_n:
+    case SHAPE_ternary_qq_opt_n:
       return true;
     }
   gcc_unreachable ();
@@ -1704,6 +1838,7 @@ gimple_folder::fold ()
     case FUNC_svasrd:
     case FUNC_svdiv:
     case FUNC_svdivr:
+    case FUNC_svdot:
     case FUNC_svdup:
     case FUNC_sveor:
     case FUNC_svindex:
@@ -1800,6 +1935,9 @@ function_expander::expand ()
     case FUNC_svdivr:
       return expand_div (true);
 
+    case FUNC_svdot:
+      return expand_dot ();
+
     case FUNC_svdup:
       return expand_dup ();
 
@@ -1930,6 +2068,16 @@ function_expander::expand_div (bool reversed_p)
   return expand_signed_pred_op (DIV, UDIV, UNSPEC_COND_DIV, merge_argno);
 }
 
+/* Expand a call to svdot.  */
+rtx
+function_expander::expand_dot ()
+{
+  if (type_suffixes[m_fi.types[0]].unsigned_p)
+    return expand_via_unpred_direct_optab (udot_prod_optab);
+  else
+    return expand_via_unpred_direct_optab (sdot_prod_optab);
+}
+
 /* Expand a call to svdup.  */
 rtx
 function_expander::expand_dup ()
diff --git a/gcc/config/aarch64/aarch64-sve-builtins.def b/gcc/config/aarch64/aarch64-sve-builtins.def
index b855e95..0977d4a 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.def
+++ b/gcc/config/aarch64/aarch64-sve-builtins.def
@@ -67,6 +67,7 @@ DEF_SVE_FUNCTION (svand, binary_opt_n, all_integer, mxz)
 DEF_SVE_FUNCTION (svasrd, shift_right_imm, all_signed, mxz)
 DEF_SVE_FUNCTION (svdiv, binary_opt_n, all_sdi_and_float, mxz)
 DEF_SVE_FUNCTION (svdivr, binary_opt_n, all_sdi_and_float, mxz)
+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)
diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md
index 42a77dd..cbf9a7f 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -3839,3 +3839,17 @@
    insr\t%0.<Vetype>, %<vwcore>2
    insr\t%0.<Vetype>, %<Vetype>2"
 )
+
+;; Unpredicated DOT product.
+(define_insn "<sur>dot_prod<mode>"
+  [(set (match_operand:SVE_SDI 0 "register_operand" "=w, ?&w")
+	(plus:SVE_SDI (unspec:SVE_SDI [(match_operand:<VSI2QI> 2 "register_operand" "w, w")
+				       (match_operand:<VSI2QI> 3 "register_operand" "w, w")]
+		       DOTPROD)
+	(match_operand:SVE_SDI 1 "register_operand" "0, w")))]
+  "TARGET_SVE"
+  "@
+   <sur>dot\\t%0.<Vetype>, %2.<Vetype_fourth>, %3.<Vetype_fourth>
+   movprfx\t%0, %1\;<sur>dot\\t%0.<Vetype>, %2.<Vetype_fourth>, %3.<Vetype_fourth>"
+  [(set_attr "movprfx" "*,yes")]
+)
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index fe1a92f..14d6811 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -662,6 +662,9 @@
 			  (QI "b")   (HI "h")
 			  (SI "s")   (DI "d")])
 
+;; Mode to one fourth individual element type mapping used in instruction DOT.
+(define_mode_attr Vetype_fourth [(VNx4SI "b") (VNx2DI "h")])
+
 ;; Equivalent of "size" for a vector element.
 (define_mode_attr Vesize [(VNx16QI "b")
 			  (VNx8HI  "h") (VNx8HF  "h")
@@ -1029,7 +1032,8 @@
 		      (V4HF "v") (V8HF  "v")])
 
 (define_mode_attr vsi2qi [(V2SI "v8qi") (V4SI "v16qi")])
-(define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI")])
+(define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI")
+			  (VNx4SI "VNx16QI") (VNx2DI "VNx8HI")])
 
 
 ;; Register suffix for DOTPROD input types from the return type.
diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C
new file mode 100644
index 0000000..309c930
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h" /* { dg-message "initializing argument 2" } */
+
+svuint32_t
+f1 (svuint32_t x, svint8_t y, svuint8_t z)
+{
+  return svdot_u32 (x, y, z); /* { dg-error "cannot convert 'svint8_t' to 'svuint8_t'" } */
+}
diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C
new file mode 100644
index 0000000..984b45f
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h"
+/* { dg-message {note: candidate: 'svuint32_t svdot\(svuint32_t, svuint8_t, svuint8_t\)'} "" { target *-*-* } 3 } */
+/* { dg-message {note: *candidate expects 3 arguments, 2 provided} "" { target *-*-* } 3 } */
+/* { dg-message {note: *no known conversion for argument 2 from 'svuint32_t' to 'svuint8_t'} "" { target *-*-* } 3 } */
+/* { dg-message {note: *no known conversion for argument 1 from 'int' to 'svuint32_t'} "" { target *-*-* } 3 } */
+/* { dg-message {note: *no known conversion for argument 2 from 'svint8_t' to 'svuint8_t'} "" { target *-*-* } 3 } */
+
+void
+f1 (svuint32_t x, svint8_t y, svuint8_t z)
+{
+  svdot (x, y); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svint8_t&\)'} } */
+  svdot (x, x, x); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svuint32_t&, svuint32_t&\)'} } */
+  svdot (1, z, z); /* { dg-error {no matching function for call to 'svdot\(int, svuint8_t&, svuint8_t&\)'} } */
+  svdot (x, y, z); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svint8_t&, svuint8_t&\)'} } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c
new file mode 100644
index 0000000..599a926
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** dot_s32_tied1:
+**	sdot	z0\.s, z16\.b, z17\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_s32_tied1, svint32_t, svint8_t,
+	     z0 = svdot_s32 (z0, z16, z17),
+	     z0 = svdot (z0, z16, z17))
+
+/*
+** dot_s32_tied2:
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	sdot	z16\.s, \1\.b, z17\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_s32_tied2, svint32_t, svint8_t,
+	     z16_res = svdot_s32 (z0, z16, z17),
+	     z16_res = svdot (z0, z16, z17))
+
+/*
+** dot_s32_tied3:
+**	mov	(z[0-9]+)\.d, z17\.d
+**	movprfx	z17, z0
+**	sdot	z17\.s, z16\.b, \1\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_s32_tied3, svint32_t, svint8_t,
+	     z17_res = svdot_s32 (z0, z16, z17),
+	     z17_res = svdot (z0, z16, z17))
+
+/*
+** dot_s32_untied:
+**	movprfx	z0, z1
+**	sdot	z0\.s, z16\.b, z17\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_s32_untied, svint32_t, svint8_t,
+	     z0 = svdot_s32 (z1, z16, z17),
+	     z0 = svdot (z1, z16, z17))
+
+/*
+** dot_w0_s32_tied1:
+**	mov	(z[0-9]+\.b), w0
+**	sdot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_s32_tied1, svint32_t, svint8_t, int8_t,
+	      z0 = svdot_n_s32 (z0, z16, x0),
+	      z0 = svdot (z0, z16, x0))
+
+/*
+** dot_w0_s32_tied2:
+**	mov	(z[0-9]+\.b), w0
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	sdot	z16\.s, \2\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_s32_tied2, svint32_t, svint8_t, int8_t,
+	      z16_res = svdot_n_s32 (z0, z16, x0),
+	      z16_res = svdot (z0, z16, x0))
+
+/*
+** dot_w0_s32_untied:
+**	mov	(z[0-9]+\.b), w0
+**	movprfx	z0, z1
+**	sdot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_s32_untied, svint32_t, svint8_t, int8_t,
+	      z0 = svdot_n_s32 (z1, z16, x0),
+	      z0 = svdot (z1, z16, x0))
+
+/*
+** dot_b0_s32_untied:
+**	mov	(z[0-9]+\.b), b0
+**	movprfx	z1, z0
+**	sdot	z1\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_b0_s32_untied, svint32_t, svint8_t, int8_t,
+	      z1 = svdot_n_s32 (z0, z16, d0),
+	      z1 = svdot (z0, z16, d0))
+
+/*
+** dot_2_s32_untied:
+**	mov	(z[0-9]+\.b), #2
+**	movprfx	z0, z1
+**	sdot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_Z (dot_2_s32_untied, svint32_t, svint8_t,
+	     z0 = svdot_n_s32 (z1, z16, 2),
+	     z0 = svdot (z1, z16, 2))
+
+/*
+** dot_m1_s32:
+**	mov	(z[0-9]+\.b), #-1
+**	sdot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_Z (dot_m1_s32, svint32_t, svint8_t,
+	     z0 = svdot_n_s32 (z0, z16, -1),
+	     z0 = svdot (z0, z16, -1))
+
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c
new file mode 100644
index 0000000..4bcdde9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** dot_s64_tied1:
+**	sdot	z0\.d, z16\.h, z17\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_s64_tied1, svint64_t, svint16_t,
+	     z0 = svdot_s64 (z0, z16, z17),
+	     z0 = svdot (z0, z16, z17))
+
+/*
+** dot_s64_tied2:
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	sdot	z16\.d, \1\.h, z17\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_s64_tied2, svint64_t, svint16_t,
+	     z16_res = svdot_s64 (z0, z16, z17),
+	     z16_res = svdot (z0, z16, z17))
+
+/*
+** dot_s64_tied3:
+**	mov	(z[0-9]+)\.d, z17\.d
+**	movprfx	z17, z0
+**	sdot	z17\.d, z16\.h, \1\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_s64_tied3, svint64_t, svint16_t,
+	     z17_res = svdot_s64 (z0, z16, z17),
+	     z17_res = svdot (z0, z16, z17))
+
+/*
+** dot_s64_untied:
+**	movprfx	z0, z1
+**	sdot	z0\.d, z16\.h, z17\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_s64_untied, svint64_t, svint16_t,
+	     z0 = svdot_s64 (z1, z16, z17),
+	     z0 = svdot (z1, z16, z17))
+
+/*
+** dot_w0_s64_tied1:
+**	mov	(z[0-9]+\.h), w0
+**	sdot	z0\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_s64_tied1, svint64_t, svint16_t, int16_t,
+	      z0 = svdot_n_s64 (z0, z16, x0),
+	      z0 = svdot (z0, z16, x0))
+
+/*
+** dot_w0_s64_tied2:
+**	mov	(z[0-9]+\.h), w0
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	sdot	z16\.d, \2\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_s64_tied2, svint64_t, svint16_t, int16_t,
+	      z16_res = svdot_n_s64 (z0, z16, x0),
+	      z16_res = svdot (z0, z16, x0))
+
+/*
+** dot_w0_s64_untied:
+**	mov	(z[0-9]+\.h), w0
+**	movprfx	z0, z1
+**	sdot	z0\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_s64_untied, svint64_t, svint16_t, int16_t,
+	      z0 = svdot_n_s64 (z1, z16, x0),
+	      z0 = svdot (z1, z16, x0))
+
+/*
+** dot_h0_s64_untied:
+**	mov	(z[0-9]+\.h), h0
+**	movprfx	z1, z0
+**	sdot	z1\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_h0_s64_untied, svint64_t, svint16_t, int16_t,
+	      z1 = svdot_n_s64 (z0, z16, d0),
+	      z1 = svdot (z0, z16, d0))
+
+/*
+** dot_2_s64_untied:
+**	mov	(z[0-9]+\.h), #2
+**	movprfx	z0, z1
+**	sdot	z0\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_Z (dot_2_s64_untied, svint64_t, svint16_t,
+	     z0 = svdot_n_s64 (z1, z16, 2),
+	     z0 = svdot (z1, z16, 2))
+
+/*
+** dot_m1_s64:
+**	mov	(z[0-9]+)\.b, #-1
+**	sdot	z0\.d, z16\.h, \1\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_m1_s64, svint64_t, svint16_t,
+	     z0 = svdot_n_s64 (z0, z16, -1),
+	     z0 = svdot (z0, z16, -1))
+
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c
new file mode 100644
index 0000000..831b49d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** dot_u32_tied1:
+**	udot	z0\.s, z16\.b, z17\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_u32_tied1, svuint32_t, svuint8_t,
+	     z0 = svdot_u32 (z0, z16, z17),
+	     z0 = svdot (z0, z16, z17))
+
+/*
+** dot_u32_tied2:
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	udot	z16\.s, \1\.b, z17\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_u32_tied2, svuint32_t, svuint8_t,
+	     z16_res = svdot_u32 (z0, z16, z17),
+	     z16_res = svdot (z0, z16, z17))
+
+/*
+** dot_u32_tied3:
+**	mov	(z[0-9]+)\.d, z17\.d
+**	movprfx	z17, z0
+**	udot	z17\.s, z16\.b, \1\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_u32_tied3, svuint32_t, svuint8_t,
+	     z17_res = svdot_u32 (z0, z16, z17),
+	     z17_res = svdot (z0, z16, z17))
+
+/*
+** dot_u32_untied:
+**	movprfx	z0, z1
+**	udot	z0\.s, z16\.b, z17\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_u32_untied, svuint32_t, svuint8_t,
+	     z0 = svdot_u32 (z1, z16, z17),
+	     z0 = svdot (z1, z16, z17))
+
+/*
+** dot_w0_u32_tied1:
+**	mov	(z[0-9]+\.b), w0
+**	udot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_u32_tied1, svuint32_t, svuint8_t, uint8_t,
+	      z0 = svdot_n_u32 (z0, z16, x0),
+	      z0 = svdot (z0, z16, x0))
+
+/*
+** dot_w0_u32_tied2:
+**	mov	(z[0-9]+\.b), w0
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	udot	z16\.s, \2\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_u32_tied2, svuint32_t, svuint8_t, uint8_t,
+	      z16_res = svdot_n_u32 (z0, z16, x0),
+	      z16_res = svdot (z0, z16, x0))
+
+/*
+** dot_w0_u32_untied:
+**	mov	(z[0-9]+\.b), w0
+**	movprfx	z0, z1
+**	udot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_u32_untied, svuint32_t, svuint8_t, uint8_t,
+	      z0 = svdot_n_u32 (z1, z16, x0),
+	      z0 = svdot (z1, z16, x0))
+
+/*
+** dot_b0_u32_untied:
+**	mov	(z[0-9]+\.b), b0
+**	movprfx	z1, z0
+**	udot	z1\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_b0_u32_untied, svuint32_t, svuint8_t, uint8_t,
+	      z1 = svdot_n_u32 (z0, z16, d0),
+	      z1 = svdot (z0, z16, d0))
+
+/*
+** dot_2_u32_untied:
+**	mov	(z[0-9]+\.b), #2
+**	movprfx	z0, z1
+**	udot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_Z (dot_2_u32_untied, svuint32_t, svuint8_t,
+	     z0 = svdot_n_u32 (z1, z16, 2),
+	     z0 = svdot (z1, z16, 2))
+
+/*
+** dot_m1_u32:
+**	mov	(z[0-9]+\.b), #-1
+**	udot	z0\.s, z16\.b, \1
+**	ret
+*/
+TEST_DUAL_Z (dot_m1_u32, svuint32_t, svuint8_t,
+	     z0 = svdot_n_u32 (z0, z16, -1),
+	     z0 = svdot (z0, z16, -1))
+
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c
new file mode 100644
index 0000000..8f22ad5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c
@@ -0,0 +1,111 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sve_acle.h"
+
+/*
+** dot_u64_tied1:
+**	udot	z0\.d, z16\.h, z17\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_u64_tied1, svuint64_t, svuint16_t,
+	     z0 = svdot_u64 (z0, z16, z17),
+	     z0 = svdot (z0, z16, z17))
+
+/*
+** dot_u64_tied2:
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	udot	z16\.d, \1\.h, z17\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_u64_tied2, svuint64_t, svuint16_t,
+	     z16_res = svdot_u64 (z0, z16, z17),
+	     z16_res = svdot (z0, z16, z17))
+
+/*
+** dot_u64_tied3:
+**	mov	(z[0-9]+)\.d, z17\.d
+**	movprfx	z17, z0
+**	udot	z17\.d, z16\.h, \1\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_u64_tied3, svuint64_t, svuint16_t,
+	     z17_res = svdot_u64 (z0, z16, z17),
+	     z17_res = svdot (z0, z16, z17))
+
+/*
+** dot_u64_untied:
+**	movprfx	z0, z1
+**	udot	z0\.d, z16\.h, z17\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_u64_untied, svuint64_t, svuint16_t,
+	     z0 = svdot_u64 (z1, z16, z17),
+	     z0 = svdot (z1, z16, z17))
+
+/*
+** dot_w0_u64_tied1:
+**	mov	(z[0-9]+\.h), w0
+**	udot	z0\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_u64_tied1, svuint64_t, svuint16_t, uint16_t,
+	      z0 = svdot_n_u64 (z0, z16, x0),
+	      z0 = svdot (z0, z16, x0))
+
+/*
+** dot_w0_u64_tied2:
+**	mov	(z[0-9]+\.h), w0
+**	mov	(z[0-9]+)\.d, z16\.d
+**	movprfx	z16, z0
+**	udot	z16\.d, \2\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_u64_tied2, svuint64_t, svuint16_t, uint16_t,
+	      z16_res = svdot_n_u64 (z0, z16, x0),
+	      z16_res = svdot (z0, z16, x0))
+
+/*
+** dot_w0_u64_untied:
+**	mov	(z[0-9]+\.h), w0
+**	movprfx	z0, z1
+**	udot	z0\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_w0_u64_untied, svuint64_t, svuint16_t, uint16_t,
+	      z0 = svdot_n_u64 (z1, z16, x0),
+	      z0 = svdot (z1, z16, x0))
+
+/*
+** dot_h0_u64_untied:
+**	mov	(z[0-9]+\.h), h0
+**	movprfx	z1, z0
+**	udot	z1\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_ZS (dot_h0_u64_untied, svuint64_t, svuint16_t, uint16_t,
+	      z1 = svdot_n_u64 (z0, z16, d0),
+	      z1 = svdot (z0, z16, d0))
+
+/*
+** dot_2_u64_untied:
+**	mov	(z[0-9]+\.h), #2
+**	movprfx	z0, z1
+**	udot	z0\.d, z16\.h, \1
+**	ret
+*/
+TEST_DUAL_Z (dot_2_u64_untied, svuint64_t, svuint16_t,
+	     z0 = svdot_n_u64 (z1, z16, 2),
+	     z0 = svdot (z1, z16, 2))
+
+/*
+** dot_m1_u64:
+**	mov	(z[0-9]+)\.b, #-1
+**	udot	z0\.d, z16\.h, \1\.h
+**	ret
+*/
+TEST_DUAL_Z (dot_m1_u64, svuint64_t, svuint16_t,
+	     z0 = svdot_n_u64 (z0, z16, -1),
+	     z0 = svdot (z0, z16, -1))
+
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 f91f26f..07b110c 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
@@ -26,6 +26,8 @@
      asm volatile ("" :: "r" (XN))
 #  define BIND_OUTPUT_D(DN) \
      asm volatile ("" :: "w" (DN))
+#  define DECLARE_RESULT(TYPE, ZN) \
+     register TYPE ZN##_res asm (#ZN)
 #else
 #  define BIND_INPUT_Z(TYPE, ZN) TYPE ZN
 #  define BIND_INPUT_P(PN) svbool_t PN
@@ -35,6 +37,7 @@
 #  define BIND_OUTPUT_P(PN) (void) PN
 #  define BIND_OUTPUT_X(XN) (void) XN
 #  define BIND_OUTPUT_D(DN) (void) DN
+#  define DECLARE_RESULT(TYPE, ZN) TYPE ZN##_res
 #endif
 
 #if defined (TEST_OVERLOADS)
@@ -52,6 +55,16 @@
   BIND_INPUT_Z (TYPE, z3);			\
   BIND_INPUT_Z (TYPE, z4)
 
+#define BIND_INPUT_ZS_FROM_Z16(TYPE)		\
+  BIND_INPUT_Z (TYPE, z16);			\
+  BIND_INPUT_Z (TYPE, z17);			\
+  BIND_INPUT_Z (TYPE, z18)			\
+
+#define DECLARE_RESULT_ZS_FROM_Z16(TYPE)	\
+  DECLARE_RESULT (TYPE, z16);			\
+  DECLARE_RESULT (TYPE, z17);			\
+  DECLARE_RESULT (TYPE, z18)
+
 #define BIND_OUTPUT_ZS				\
   BIND_OUTPUT_Z (z0);				\
   BIND_OUTPUT_Z (z1);				\
@@ -73,6 +86,11 @@
   BIND_OUTPUT_P (p3);				\
   BIND_OUTPUT_P (p4)
 
+#define BIND_RESULT_ZS_FROM_Z16			\
+  BIND_OUTPUT_Z (z16_res);			\
+  BIND_OUTPUT_Z (z17_res);			\
+  BIND_OUTPUT_Z (z18_res)
+
 #ifdef __cplusplus
 #define START(NAME) extern "C" void NAME (void); void NAME (void)
 #else
@@ -89,6 +107,19 @@
     BIND_OUTPUT_P (p0);					\
   }
 
+#define TEST_DUAL_Z(NAME, TYPE1, TYPE2, CODE1, CODE2)	\
+  START (NAME)						\
+  {							\
+    BIND_INPUT_ZS (TYPE1);				\
+    BIND_INPUT_ZS_FROM_Z16 (TYPE2);			\
+    DECLARE_RESULT_ZS_FROM_Z16 (TYPE1);			\
+    BIND_INPUT_P (p0);					\
+    INVOKE (CODE1, CODE2);				\
+    BIND_OUTPUT_ZS;					\
+    BIND_OUTPUT_P (p0);					\
+    BIND_RESULT_ZS_FROM_Z16;				\
+  }
+
 #define TEST_UNIFORM_ZS(NAME, ZTYPE, STYPE, CODE1, CODE2)	\
   START (NAME)							\
   {								\
@@ -103,6 +134,23 @@
     BIND_OUTPUT_P (p0);						\
   }
 
+#define TEST_DUAL_ZS(NAME, ZTYPE1, ZTYPE2, STYPE, CODE1, CODE2)	\
+  START (NAME)							\
+  {								\
+    BIND_INPUT_ZS (ZTYPE1);					\
+    BIND_INPUT_ZS_FROM_Z16 (ZTYPE2);				\
+    DECLARE_RESULT_ZS_FROM_Z16 (ZTYPE1);			\
+    BIND_INPUT_P (p0);						\
+    BIND_INPUT_X (STYPE, x0);					\
+    BIND_INPUT_D (STYPE, d0);					\
+    INVOKE (CODE1, CODE2);					\
+    BIND_OUTPUT_ZS;						\
+    BIND_OUTPUT_X (x0);						\
+    BIND_OUTPUT_D (d0);						\
+    BIND_OUTPUT_P (p0);						\
+    BIND_RESULT_ZS_FROM_Z16;					\
+  }
+
 #define TEST_P(NAME, CODE1, CODE2)	\
   START (NAME)				\
   {					\
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c
new file mode 100644
index 0000000..b25d6d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c
@@ -0,0 +1,13 @@
+
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h" /* { dg-message "note: expected 'svuint8_t' but argument is of type 'svuint32_t'" } */
+
+svint32_t
+f1 (svbool_t pg, svuint32_t x, svuint8_t y, svuint8_t z)
+{
+  svdot_u32 (x, y, x); /* { dg-error "incompatible type for argument 3 of 'svdot_u32'" } */
+  svdot_u32 (x); /* { dg-error "too few arguments to function 'svdot_u32'" } */
+  svdot_u32 (x, y, z, x); /* { dg-error "too many arguments to function 'svdot_u32'" } */
+  return svdot_u32 (x, y, z); /* { dg-error "incompatible types when returning type 'svuint32_t' but 'svint32_t' was expected" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c
new file mode 100644
index 0000000..db1b41a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c
@@ -0,0 +1,15 @@
+
+/* { dg-do compile } */
+
+#pragma GCC aarch64 "arm_sve.h"
+
+void
+f1 (svuint32_t x, svuint8_t y, svint8_t z)
+{
+  svdot (x); /* { dg-error "too few arguments to function 'svdot'" } */
+  svdot (x, y, y, y); /* { dg-error "too many arguments to function 'svdot'" } */
+  svdot (x, y, z); /* { dg-error "passing 'svint8_t' to argument 3 of 'svdot', which expects 'svuint8_t'" } */
+  svdot (x, x, x); /* { dg-error "passing 'svuint32_t' to argument 2 of 'svdot', which expects 'svuint8_t'" } */
+  svdot (1, y, y); /* { dg-error "passing 'int' to argument 1 of 'svdot', which expects an SVE vector type" } */
+  svdot (y, y, y); /* { dg-error "'svdot' has no form that takes 'svuint8_t' arguments" } */
+}
-- 
2.7.4

