> -----Original Message-----
> From: [email protected] <[email protected]>
> Sent: 09 September 2026 19:12
> To: [email protected]
> Cc: Tamar Christina <[email protected]>; [email protected];
> [email protected]; Ezra Sitorus <[email protected]>
> Subject: [RFC PATCH 3/5] gcc: Add new COMPLEX_DOT_PROD_ROT0
> IFN/optabs
>
> From: Ezra Sitorus <[email protected]>
>
> Add new internal function COMPLEX_DOT_PROD_ROT0 and optab
> cdot_prod_rot0_optab
> to represent complex integer dot product.
>
> COMPLEX_DOT_PROD_ROT0 (A, B, ACC) is a lane-reducing signed integer
> complex
> dot product. The 2 input vectors contain interleaved W-bit real and imaginary
> components in even/odd numbered lanes respectively. Each 4W-bit result
> element
> accumulates the 0-rotation products of the 2 complex input pairs in the
> corresponding group of 4 input lanes:
>
> result[j] = acc[j]
> + a[k].re * b[k].re
> - a[k].im * b[k].im
> + a[k + 1].re * b[k + 1].re
> - a[k + 1].im * b[k + 1].im
>
> where 2*j = k.
>
> 0-rotation means that the imaginary components in the second source vector
> are
> negated, and so the overall operation is accumulating the real part of the
> complex dot product. Other rotations can be added in future patches.
>
> In internal-fn.cc: complex_dot_prod_direct is defined to { -1, 1, false }
> because it uses the return type as the accumulator/result type and the input
> type is either of the narrower source type.
>
> In AArch64, this corresponds to the CDOT instruction. This patch also teaches
> GCC to convert the optab into the correct define_insn pattern.
>
> gcc/ChangeLog:
> * config/aarch64/aarch64-sve2.md
> (cdot_prod_rot0<mode><vsi2qi>): New
> define_expand.
> * internal-fn.cc (complex_dot_prod_direct): New static initializers.
> * internal-fn.def (COMPLEX_DOT_PROD_ROT0) New internal
> function.
> * optabs.def (cdot_prod_rot0_optab): New optab.
> ---
> gcc/config/aarch64/aarch64-sve2.md | 10 ++++++++++
> gcc/internal-fn.cc | 5 +++++
> gcc/internal-fn.def | 1 +
> gcc/optabs.def | 1 +
The new optabs and IFN need to be documented in ifn.texi and md.texi
and split the aarch64 implementation to it's own patch.
But why not add the other rotations at the same time?
We'd likely also later (in a different patch) need cdot_prod and cdot_prod_conj,
because then both lanes are visible the SLP tree will look much different. i.e.
#include <stdint.h>
typedef _Complex int8_t cint16_t;
typedef _Complex int32_t cint32_t;
cint32_t cdot(cint16_t *a, cint16_t *b, uint32_t N)
{
cint32_t res = 0;
for (uint32_t i = 0; i < N; i++)
res += a[i] * b[i];
return res;
}
> 4 files changed, 17 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64-sve2.md
> b/gcc/config/aarch64/aarch64-sve2.md
> index c33df283cc2a..ad4febb60bf8 100644
> --- a/gcc/config/aarch64/aarch64-sve2.md
> +++ b/gcc/config/aarch64/aarch64-sve2.md
> @@ -3578,6 +3578,16 @@
> ;; - CDOT
> ;; -------------------------------------------------------------------------
>
> +(define_expand "cdot_prod_rot0<mode><vsi2qi>"
> + [(set (match_operand:SVE_FULL_SDI 0 "register_operand")
> + (unspec:SVE_FULL_SDI
> + [(match_operand:SVE_FULL_SDI 3 "register_operand")
> + (match_operand:<VSI2QI> 1 "register_operand")
> + (match_operand:<VSI2QI> 2 "register_operand")]
> + UNSPEC_CDOT))]
> + "TARGET_SVE2"
> +)
> +
> (define_insn "@aarch64_sve_<optab><mode>"
> [(set (match_operand:SVE_FULL_SDI 0 "register_operand")
> (unspec:SVE_FULL_SDI
> diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
> index c57b594ac591..cc968109261b 100644
> --- a/gcc/internal-fn.cc
> +++ b/gcc/internal-fn.cc
> @@ -180,6 +180,7 @@ init_internal_fns ()
> #define unary_convert_direct { -1, 0, true }
> #define binary_direct { 0, 0, true }
> #define ternary_direct { 0, 0, true }
> +#define complex_dot_prod_direct { -1, 1, false }
> #define cond_unary_direct { 1, 1, true }
> #define cond_binary_direct { 1, 1, true }
> #define cond_ternary_direct { 1, 1, true }
> @@ -4315,6 +4316,9 @@ expand_reduc_sbool_optab_fn (internal_fn fn,
> gcall *stmt, direct_optab optab)
> #define expand_select_vl_optab_fn(FN, STMT, OPTAB) \
> expand_convert_optab_fn (FN, STMT, OPTAB, 3)
>
> +#define expand_complex_dot_prod_optab_fn(FN, STMT, OPTAB) \
> + expand_convert_optab_fn (FN, STMT, OPTAB, 3)
> +
> /* Expanders for optabs that can use expand_convert_optab_fn. */
>
> #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \
> @@ -4398,6 +4402,7 @@ multi_vector_optab_supported_p (convert_optab
> optab, tree_pair types,
> #define direct_unary_convert_optab_supported_p
> convert_optab_supported_p
> #define direct_binary_optab_supported_p direct_optab_supported_p
> #define direct_ternary_optab_supported_p direct_optab_supported_p
> +#define direct_complex_dot_prod_optab_supported_p
> convert_optab_supported_p
> #define direct_cond_unary_optab_supported_p direct_optab_supported_p
> #define direct_cond_binary_optab_supported_p direct_optab_supported_p
> #define direct_cond_ternary_optab_supported_p direct_optab_supported_p
> diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
> index af9f92950c73..08bdedc30045 100644
> --- a/gcc/internal-fn.def
> +++ b/gcc/internal-fn.def
> @@ -453,6 +453,7 @@ DEF_INTERNAL_OPTAB_FN (COMPLEX_ADD_ROT90,
> ECF_CONST, cadd90, binary)
> DEF_INTERNAL_OPTAB_FN (COMPLEX_ADD_ROT270, ECF_CONST, cadd270,
> binary)
> DEF_INTERNAL_OPTAB_FN (COMPLEX_MUL, ECF_CONST, cmul, binary)
> DEF_INTERNAL_OPTAB_FN (COMPLEX_MUL_CONJ, ECF_CONST, cmul_conj,
> binary)
> +DEF_INTERNAL_OPTAB_FN (COMPLEX_DOT_PROD_ROT0, ECF_CONST,
> cdot_prod_rot0, complex_dot_prod)
> DEF_INTERNAL_OPTAB_FN (VEC_ADDSUB, ECF_CONST, vec_addsub, binary)
> DEF_INTERNAL_OPTAB_FN (VEC_TRUNC_ADD_HIGH, ECF_CONST |
> ECF_NOTHROW,
> vec_trunc_add_high, binary)
> diff --git a/gcc/optabs.def b/gcc/optabs.def
> index 9d95f047cb50..b30e2bec6b2b 100644
> --- a/gcc/optabs.def
> +++ b/gcc/optabs.def
> @@ -114,6 +114,7 @@ OPTAB_CD(vec_init_optab, "vec_init$a$b")
> OPTAB_CD (sdot_prod_optab, "sdot_prod$I$a$b")
> OPTAB_CD (udot_prod_optab, "udot_prod$I$a$b")
> OPTAB_CD (usdot_prod_optab, "usdot_prod$I$a$b")
> +OPTAB_CD (cdot_prod_rot0_optab, "cdot_prod_rot0$I$a$b")
>
> OPTAB_CD (while_ult_optab, "while_ult$a$b")
> OPTAB_CD (select_vl_optab, "select_vl$a$b")
> --
> 2.53.0