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.