> -----Original Message-----
> From: Richard Biener <[email protected]>
> Sent: 15 September 2026 14:07
> To: Tamar Christina <[email protected]>
> Cc: Ezra Sitorus <[email protected]>; [email protected];
> [email protected]
> Subject: RE: [RFC PATCH 3/5] gcc: Add new COMPLEX_DOT_PROD_ROT0
> IFN/optabs
> 
> On Tue, 15 Sep 2026, Tamar Christina wrote:
> 
> > > -----Original Message-----
> > > From: Richard Biener <[email protected]>
> > > Sent: 15 September 2026 12:50
> > > To: Tamar Christina <[email protected]>
> > > Cc: Ezra Sitorus <[email protected]>; [email protected];
> > > [email protected]
> > > Subject: RE: [RFC PATCH 3/5] gcc: Add new COMPLEX_DOT_PROD_ROT0
> > > IFN/optabs
> > >
> > > On Tue, 15 Sep 2026, Tamar Christina wrote:
> > >
> > > > > -----Original Message-----
> > > > > From: Richard Biener <[email protected]>
> > > > > Sent: 15 September 2026 10:16
> > > > > To: Tamar Christina <[email protected]>
> > > > > Cc: Ezra Sitorus <[email protected]>; [email protected];
> > > > > [email protected]
> > > > > Subject: RE: [RFC PATCH 3/5] gcc: Add new
> COMPLEX_DOT_PROD_ROT0
> > > > > IFN/optabs
> > > > >
> > > > > On Tue, 15 Sep 2026, Tamar Christina wrote:
> > > > >
> > > > > > > -----Original Message-----
> > > > > > > From: Richard Biener <[email protected]>
> > > > > > > Sent: 15 September 2026 09:23
> > > > > > > To: Tamar Christina <[email protected]>
> > > > > > > Cc: Ezra Sitorus <[email protected]>; gcc-
> [email protected];
> > > > > > > [email protected]
> > > > > > > Subject: RE: [RFC PATCH 3/5] gcc: Add new
> > > COMPLEX_DOT_PROD_ROT0
> > > > > > > IFN/optabs
> > > > > > >
> > > > > > > On Tue, 15 Sep 2026, Tamar Christina wrote:
> > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > > > -----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.
> > > > > > >
> > > > > > > I other places we use _conj, not rot0:
> > > > > > >
> > > > > > > OPTAB_D (cmul_conj_optab, "cmul_conj$a3")
> > > > > > >
> > > > > > > so why not use that for consistency?
> > > > > >
> > > > > > That's a different operation. complex dotprod is numerically
> > > > >
> > > > > Sure, I meant why cdot_prod_rot0 rather than cdot_prod_conj,
> > > > > complex conjugate is exactly negating the imaginary part?
> > > >
> > > > Because the existing cmul/cadd/cdot *_conj optabs are intended to
> > > > represent the full mathematical complex operation which create both
> > > > the real and imaginary results.
> > > >
> > > > Yes, cdot #0 conjugates the second operand in the sense that it uses
> > > > ar * br - ai * bi.  But it only computes the real component of the
> > > > complex dot product.  The imaginary component is not computed.
> > >
> > > Oh, but then the name cdot_* is even more confusing?  Why even bother
> > > with naming it "complex" then?  It's not even a dot product?
> >
> > Agreed! Hence my ask for Ezra to document the operations so we could see
> > what they all mean.
> >
> > >
> > >       res += a[i].real * b[i].real
> > >              - a[i].imag * b[i].imag;
> > >
> > > that suggests cdot0 computes
> > >
> > >    res + x * y - z * w
> > >
> > > or is it, for vectors, even more complicates as
> > >
> > >    res + x[2*n] * y[2*n] - x[2*n+1] * y[2*n+1]
> > >
> > > ?  Aka it's an alternating plus/minus non-"complex" dot-product
> > >
> > >   (res + x[2*n] * y[2*n]) - x[2*n+1] * y[2*n+1]
> >
> > Yeah.
> >
> > >
> > > as if negating every other lane in x[] and then using a regular
> > > (non-complex) dot product?  And it's also a reduction, so
> > > reduc_dot_<?>_scal?  with <?> standing for whatever we invent
> > > for the alternating negation (we have vec_addsub and vec_fmaddsub
> > > and vec_fmsubadd for example, but that's not reductions).
> > >
> >
> > Yeah, reduc_dot_addsub_scal sounds quite funky hehe. Is the "dot" in
> > that case relevant? Why not just reduc_dot_addsub_scal?  But that said
> > my issue is still I'm not sure this scales to the other operations.
> >
> > Like rot90 is
> >
> > res + x[2*n] * y[2*n+1] + x[2*n+1] * y[2*n]
> >
> > so do we do reduc_dot_addadd_scal or reduc_addadd_scal? That's why
> > we just kept the rot0 in the name before on BZ.
> 
> So there's still the question - is the "accumulator" really a scalar
> or is it a vector?  From reading the SVE2 'CDOT' docs it appears
> that it's a vector but with half of the lanes as  the input
> vectors?

This instruction's pseudo-code is particular hard to read.
It's definitely widening, every reduction reads 8 input elements.

> 
> So _scal would be inappropriate.  Instead it would be a
> lane-reducing (but not widening?  CDOT is an integer vector operation?)
> operation?  In which case reduc_dot_addsub.  Or if we want to
> stick with 'cdot' and 'rot' maybe cdot_rot0_real and while
> the docs say rot90 is _imag it's rotated to real position, so
> cdot_rot90_real as well (only _real would remain).  Or
> cdot_real and cdot_imag.  But then the other rotates would have
> to be _conj in addition to _real and _imag?
> 
> Bah.
> 
> But it's still lane-reducing(?), so reduc_cdot_rot0_real?
> 
> :/

Wait, I need pen and paper as I'm getting confused.
I'll be back tomorrow.

Thanks,
Tamar

> 
> > > I see you are following the aarch64 SVE2 'CDOT' instruction
> > > notation with its #rotate specification.  I'm a bit unsure
> > > how to translate that appropriately also given the unfortunate(?)
> > > choice to compute a "packed" real part from two-component inputs.
> > >
> >
> > Yeah there's also the unfortunate issue that extracting just the real
> > results still requires a vec_select due to the pack representation.
> >
> > Thanks,
> > Tamar
> >
> > >
> > > > For example, cmul_conj today lowers to both:
> > > >
> > > >     fcmla #180
> > > >     fcmla #270
> > > >
> > > > because both operations are needed to compute the full complex
> multiply
> > > > by a conjugated operand.
> > > >
> > > > Similarly, computing both components of a complex dot product would
> need
> > > > Two instructions and rotations:
> > > >
> > > >     cdot #0
> > > >     cdot #90
> > > >
> > > > So naming the single cdot #0 operation cdot_prod_conj would be
> > > > misleading: it suggests the optab computes the full conjugated complex
> > > > dot product, whereas it only computes one rotated component.
> > > >
> > > > This is the same distinction as for complex multiply rotations, 
> > > > discussed
> > > > in PR121925, where we settled on the "rot" suffix for the lane-rotation
> > > forms.
> > > >
> > > > This isn't dissimilar to complex multiply and rotate which we discussed
> here
> > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121925 and settled on the
> > > "rot" suffix for them.
> > > >
> > > > Thanks,
> > > > Tamar
> > > > >
> > > > > > #include <stdint.h>
> > > > > >
> > > > > > typedef struct {
> > > > > >     int8_t real;
> > > > > >     int8_t imag;
> > > > > > } cint16_t;
> > > > > >
> > > > > > typedef struct {
> > > > > >     int32_t real;
> > > > > >     int32_t imag;
> > > > > > } cint32_t;
> > > > > >
> > > > > > cint32_t cdot(cint16_t *a, cint16_t *b, uint32_t N)
> > > > > > {
> > > > > >     cint32_t res = {0, 0};
> > > > > >
> > > > > >     for (uint32_t i = 0; i < N; i++) {
> > > > > >         res.real += a[i].real * b[i].real
> > > > > >                   - a[i].imag * b[i].imag;
> > > > > >
> > > > > >         res.imag += a[i].real * b[i].imag
> > > > > >                   + a[i].imag * b[i].real;
> > > > > >     }
> > > > > >
> > > > > >     return res;
> > > > > > }
> > > > > >
> > > > > > Which would be what we'd call cdot.
> > > > > >
> > > > > > cdot_conj would be
> > > > > >
> > > > > > #include <stdint.h>
> > > > > >
> > > > > > typedef struct {
> > > > > >     int8_t real;
> > > > > >     int8_t imag;
> > > > > > } cint16_t;
> > > > > >
> > > > > > typedef struct {
> > > > > >     int32_t real;
> > > > > >     int32_t imag;
> > > > > > } cint32_t;
> > > > > >
> > > > > > cint32_t cdot_conj(const cint16_t *a,
> > > > > >                    const cint16_t *b,
> > > > > >                    uint32_t N)
> > > > > > {
> > > > > >     cint32_t res = {0, 0};
> > > > > >
> > > > > >     for (uint32_t i = 0; i < N; i++) {
> > > > > >         res.real += a[i].real * b[i].real
> > > > > >                   + a[i].imag * b[i].imag;
> > > > > >
> > > > > >         res.imag += a[i].real * b[i].imag
> > > > > >                   - a[i].imag * b[i].real;
> > > > > >     }
> > > > > >
> > > > > >     return res;
> > > > > > }
> > > > > >
> > > > > > i.e. normal dual lane operations.
> > > > > >
> > > > > > however this patch recognizes the single lane reduction,
> > > > > >
> > > > > > #include <stdint.h>
> > > > > >
> > > > > > typedef struct {
> > > > > >     int8_t real;
> > > > > >     int8_t imag;
> > > > > > } cint16_t;
> > > > > >
> > > > > > int32_t cdot0(const cint16_t *a, const cint16_t *b, uint32_t N)
> > > > > > {
> > > > > >     int32_t res = 0;
> > > > > >
> > > > > >     for (uint32_t i = 0; i < N; i++)
> > > > > >         res += a[i].real * b[i].real
> > > > > >              - a[i].imag * b[i].imag;
> > > > > >
> > > > > >     return res;
> > > > > > }
> > > > > >
> > > > > > Which is not numerically a complex dot product.  Note that the end
> goal
> > > > > > is to recognize all of these.
> > > > > >
> > > > > > Thanks,
> > > > > > Tamar
> > > > > > >
> > > > > > > > > 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
> > > > > > > >
> > > > > > > >
> > > > > > >
> > > > > > > --
> > > > > > > Richard Biener <[email protected]>
> > > > > > > SUSE Software Solutions Germany GmbH,
> > > > > > > Frankenstrasse 146, 90461 Nuernberg, Germany;
> > > > > > > GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG
> > > Nuernberg)
> > > > > >
> > > > >
> > > > > --
> > > > > Richard Biener <[email protected]>
> > > > > SUSE Software Solutions Germany GmbH,
> > > > > Frankenstrasse 146, 90461 Nuernberg, Germany;
> > > > > GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG
> Nuernberg)
> > > >
> > >
> > > --
> > > Richard Biener <[email protected]>
> > > SUSE Software Solutions Germany GmbH,
> > > Frankenstrasse 146, 90461 Nuernberg, Germany;
> > > GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)
> >
> 
> --
> Richard Biener <[email protected]>
> SUSE Software Solutions Germany GmbH,
> Frankenstrasse 146, 90461 Nuernberg, Germany;
> GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to