On Sun, Aug 9, 2026 at 6:19 AM Andrew Pinski <[email protected]> wrote:
>
> On Tue, Aug 4, 2026 at 3:00 AM <[email protected]> wrote:
> >
> > From: Kyrylo Tkachov <[email protected]>
> >
> > The rule folding (type) minmax ((wide_type) a, (wide_type) b) to
> > minmax (a, b) is restricted to scalars.  Extension is monotone, so it
> > commutes with the comparison and the outer truncation is exact, and the
> > argument is lanewise, so it holds for vectors unchanged.
> >
> > The vector case additionally needs the narrow operation to be available,
> > otherwise vector lowering would scalarise what used to be a single wide
> > instruction.
> >
> >   typedef int  v2si __attribute__((vector_size (8)));
> >   typedef long v2di __attribute__((vector_size (16)));
> >   v2si h (v2si a, v2si b)
> >   {
> >     v2di x = __builtin_convertvector (a, v2di);
> >     v2di y = __builtin_convertvector (b, v2di);
> >     return __builtin_convertvector (x < y ? x : y, v2si);
> >   }
> >
> > aarch64 -O3 before:
> >
> >         sshll   v0.2d, v0.2s, 0
> >         sshll   v1.2d, v1.2s, 0
> >         cmgt    v2.2d, v1.2d, v0.2d
> >         bsl     v2.16b, v0.16b, v1.16b
> >         xtn     v0.2s, v2.2d
> >
> > after:
> >
> >         smin    v0.2s, v0.2s, v1.2s
> >
> > Require the wide vector MIN or MAX to have one use.  A shared wide
> > result would otherwise gain a second narrow operation.
> >
> > Bootstrapped and tested on aarch64-none-linux-gnu.
> > Ok for trunk?
> > Thanks,
> > Kyrill
> >
> > gcc/ChangeLog:
> >
> >         * match.pd ((type) minmax ((wide_type) a, (wide_type) b)): Accept
> >         vector types, using element_precision and requiring the narrow
> >         operation to be supported.
> >
> > gcc/testsuite/ChangeLog:
> >
> >         * g++.dg/tree-ssa/vec-narrow-1.C: New test.
> >         * g++.dg/tree-ssa/vec-narrow-minmax-2.C: New test.
> >
> > Signed-off-by: Kyrylo Tkachov <[email protected]>
> > ---
> >  gcc/match.pd                                  | 20 +++++++++++++------
> >  gcc/testsuite/g++.dg/tree-ssa/vec-narrow-1.C  | 11 ++++++++++
> >  .../g++.dg/tree-ssa/vec-narrow-minmax-2.C     | 18 +++++++++++++++++
> >  3 files changed, 43 insertions(+), 6 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/vec-narrow-1.C
> >  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
> >
> > diff --git a/gcc/match.pd b/gcc/match.pd
> > index e0ec2626842..adbdda91b51 100644
> > --- a/gcc/match.pd
> > +++ b/gcc/match.pd
> > @@ -4649,17 +4649,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> >
> >  /* (type) minmax ((wide_type) a, (wide_type) b) -> minmax (a, b)
> >     when type matches the type of a and b, and wide_type is a wider
> > -   type with the same signedness as type. */
> > +   type with the same signedness as type.  Extension is monotone, so it
> > +   commutes with the comparison, and the truncation is then exact.  The
> > +   same holds lanewise for a vector, where the narrow operation has to be
> > +   available so that lowering does not scalarise it.  The wide operation
> > +   must become dead before a narrow vector operation is introduced.  */
> >  (for minmax (min max)
> > +     MINMAX (MIN_EXPR MAX_EXPR)
> >   (simplify
> > -  (convert (minmax:c (convert@2 @0) (convert@3 @1)))
> > -  (if (INTEGRAL_TYPE_P (type)
> > -       && INTEGRAL_TYPE_P (TREE_TYPE (@2))
> > +  (convert (minmax:c@4 (convert@2 @0) (convert@3 @1)))
> > +  (if (ANY_INTEGRAL_TYPE_P (type)
> > +       && ANY_INTEGRAL_TYPE_P (TREE_TYPE (@2))
> >         && types_match (type, TREE_TYPE (@0))
> >         && types_match (type, TREE_TYPE (@1))
> >         && types_match (TREE_TYPE (@2), TREE_TYPE (@3))
> > -       && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (type)
> > -       && TYPE_UNSIGNED (TREE_TYPE (@2)) == TYPE_UNSIGNED (type))
> > +       && element_precision (TREE_TYPE (@2)) > element_precision (type)
> > +       && TYPE_UNSIGNED (TREE_TYPE (@2)) == TYPE_UNSIGNED (type)
> > +       && (!VECTOR_TYPE_P (type)
> > +          || (single_use (@4)
> > +              && target_supports_op_p (type, MINMAX, optab_vector))))
> >     (minmax @0 @1))))
> >
> >  /* max (a, a + CST) -> a + CST where CST is positive.  */
> > diff --git a/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-1.C 
> > b/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-1.C
> > new file mode 100644
> > index 00000000000..de738e33c30
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-1.C
> > @@ -0,0 +1,11 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized" }
> > +// Extension is monotone, so it commutes with the comparison and the outer
> > +// truncation is exact.  The argument is lanewise, so a widened vector
> > +// MIN/MAX feeding a truncating conversion narrows.
> > +typedef int  v2si __attribute__((vector_size (8)));
> > +typedef long long v2di __attribute__((vector_size (16)));
> > +v2si f (v2si a, v2si b)
> > +{ v2di x = __builtin_convertvector (a, v2di), y = __builtin_convertvector 
> > (b, v2di);
> > +  return __builtin_convertvector (x < y ? x : y, v2si); }
> > +// { dg-final { scan-tree-dump-not "vector\\(2\\) long" "optimized" } }
>
>
> This testcase fails on x86_64.

This is needed:

diff --git a/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
b/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
index d7fb7f06f16..f51730f08a7 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
@@ -1,5 +1,6 @@
 // { dg-do compile }
 // { dg-options "-O2 -fdump-tree-optimized" }
+// { dg-additional-options "-mavx512vl -mavx512dq" { target {
i?86-*-* x86_64-*-* } } }

 typedef int v2si __attribute__((vector_size (8)));
 typedef long long v2di __attribute__((vector_size (16)));

I am checking it in.

> > diff --git a/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C 
> > b/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
> > new file mode 100644
> > index 00000000000..d7fb7f06f16
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/tree-ssa/vec-narrow-minmax-2.C
> > @@ -0,0 +1,18 @@
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized" }
> > +
> > +typedef int v2si __attribute__((vector_size (8)));
> > +typedef long long v2di __attribute__((vector_size (16)));
> > +
> > +v2si
> > +f (v2si a, v2si b, v2di *p)
> > +{
> > +  v2di x = __builtin_convertvector (a, v2di);
> > +  v2di y = __builtin_convertvector (b, v2di);
> > +  v2di z = x < y ? x : y;
> > +  *p = z;
> > +  return __builtin_convertvector (z, v2si);
> > +}
> > +
> > +// A shared wide MIN must not gain a second narrow MIN.
> > +// { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "optimized" } }
> > --
> > 2.50.1 (Apple Git-155)
> >



-- 
H.J.

Reply via email to