On Tue, Aug 11, 2026 at 2:06 PM Richard Biener
<[email protected]> wrote:
>
> On Tue, Aug 11, 2026 at 1:53 PM H.J. Lu <[email protected]> wrote:
> >
> > On Tue, Aug 11, 2026 at 7:20 PM Richard Biener
> > <[email protected]> wrote:
> > >
> > > On Tue, Aug 11, 2026 at 1:13 PM H.J. Lu <[email protected]> wrote:
> > > >
> > > > "(type) minmax ((wide_type) a, (wide_type) b) to minmax (a, b)" is
> > > > limited
> > > > to the single use of the result. It doesn't support:
> > > >
> > > > typedef int v2si __attribute__((vector_size (8)));
> > > > typedef long long v2di __attribute__((vector_size (16)));
> > > >
> > > > v2si
> > > > func (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);
> > > > }
> > > >
> > > > Change it to
> > > >
> > > > minmax ((wide_type) a, (wide_type) b) -> (wide_type) minmax (a, b)
> > > >
> > > > instead and add "(type) ((wide_type) a) -> a" for integer types. Now
> > > > we generate
> > > >
> > > > pminsd %xmm1, %xmm0
> > > > pmovsxdq %xmm0, %xmm1
> > > > movaps %xmm1, (%rdi)
> > > >
> > > > instead of
> > > >
> > > > pmovsxdq %xmm0, %xmm2
> > > > pmovsxdq %xmm1, %xmm1
> > > > movdqa %xmm2, %xmm0
> > > > movdqa %xmm2, %xmm3
> > > > pcmpgtq %xmm1, %xmm0
> > > > pblendvb %xmm0, %xmm1, %xmm3
> > > > movdqa %xmm3, %xmm0
> > > > movaps %xmm3, (%rdi)
> > > > shufps $232, %xmm3, %xmm0
> > > >
> > > > gcc/
> > >
> > > (simplify
> > > - (convert (minmax:c@4 (convert@2 @0) (convert@3 @1)))
> > > + (minmax:c (convert@2 @0) (convert@3 @1))
> > >
> > > no need for :c on minmax
> >
> > Removed.
> >
> > > (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))
> > > - && element_precision (TREE_TYPE (@2)) > element_precision (type)
> > > - && TYPE_UNSIGNED (TREE_TYPE (@2)) == TYPE_UNSIGNED (type)
> > > + && ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
> > > + && types_match (type, TREE_TYPE (@2))
> > > + && types_match (type, TREE_TYPE (@3))
> > >
> > > the last two are redundant
> >
> > Removed.
> >
> > > + && types_match (TREE_TYPE (@0), TREE_TYPE (@1))
> > > + && element_precision (TREE_TYPE (@0)) < element_precision (type)
> > > + && TYPE_UNSIGNED (TREE_TYPE (@0)) == TYPE_UNSIGNED (type)
> > >
> > > +/* (type) ((wide_type) a) -> a. */
> > > +(simplify
> > > + (convert (convert@1 @0))
> > > + (if (ANY_INTEGRAL_TYPE_P (type)
> > > + && ANY_INTEGRAL_TYPE_P (TREE_TYPE (@1))
> > > + && types_match (type, TREE_TYPE (@0))
> > > + && element_precision (type) < element_precision (TREE_TYPE (@1)))
> > > + @0))
> > >
> > > two-level conversions are already handled elsewhere, no need to add a
> > > new pattern.
> >
> > Where is it handled? Without it, I got
>
> It should be handled by
>
> /* Handle cases of two conversions in a row. */
> (for ocvt (convert float fix_trunc)
> (for icvt (convert float)
> (simplify
> (ocvt (icvt@1 @0))
> (with
> {
> ...
>
> Possibly
>
> /* In addition to the cases of two conversions in a row
> handled below, if we are converting something to its own
> type via an object of identical or wider precision, neither
> conversion is needed. */
> (if (((GIMPLE && useless_type_conversion_p (type, inside_type))
> || (GENERIC
> && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (inside_type)))
> && (((inter_int || inter_ptr) && final_int)
> || (inter_float && final_float))
> && inter_prec >= final_prec)
> (ocvt @0))
>
> is too strict in that inter_int checks INTEGRAL_TYPE_P, not
> ANY_INTEGRAL_TYPE_P.
> To avoid adjusting everything I'd add inside_any_int, etc. variables,
> otherwise
> a conservative transform would be to use ANY_INTEGRAL_TYPE_P for
> inside_int, etc.
> and replace uses with inside_int && !inside_vec, omitting !inside_vec
> for cases we have
> convinced ourselves are fine.
Just to say, inside_float and friends _do_ include vector float types
(and complex float types).
So consistency would ask for the use of ANY_INTEGRAL_TYPE and opting
out of vectors
(and complex?) explicitly where needed.
> > [hjl@gnu-zen4-1 vect-1]$ cat f.c
> > typedef int v2si __attribute__((vector_size (8)));
> > typedef long long v2di __attribute__((vector_size (16)));
> > v2si
> > f2 (v2si a)
> > {
> > v2di z = __builtin_convertvector (a, v2di);
> > return __builtin_convertvector (z, v2si);
> > }
> > [hjl@gnu-zen4-1 vect-1]$
> > /export/build/gnu/tools-build/gcc-gitlab-debug/build-x86_64-linux/gcc/xgcc
> > -B/export/build/gnu/tools-build/gcc-gitlab-debug/build-x86_64-linux/gcc/
> > -O2 -msse4 -S f.c
> > [hjl@gnu-zen4-1 vect-1]$ cat f.s
> > .file "f.c"
> > .text
> > .p2align 4
> > .globl f2
> > .type f2, @function
> > f2:
> > .LFB0:
> > .cfi_startproc
> > pmovsxdq %xmm0, %xmm0
> > shufps $232, %xmm0, %xmm0
> > ret
> > .cfi_endproc
> > .LFE0:
> > .size f2, .-f2
> > .ident "GCC: (GNU) 17.0.0 20260811 (experimental)"
> > .section .note.GNU-stack,"",@progbits
> > [hjl@gnu-zen4-1 vect-1]$
> >
> > > Richard.
> > >
> > >
> > > > PR middle-end/126784
> > > > * match.pd ((type) minmax ((wide_type) a, (wide_type) b)): Changed
> > > > to ...
> > > > (minmax ((wide_type) a, (wide_type) b)): This.
> > > > ((type) ((wide_type) a) -> a) New.
> > > >
> > > > gcc/testsuite/
> > > >
> > > > PR middle-end/126784
> > > > * g++.dg/tree-ssa/vec-narrow-1.C: Use -msse4 and require int128
> > > > for x86.
> > > > * g++.dg/tree-ssa/vec-narrow-minmax-2.C: Likewise.
> > > > * g++.target/i386/pr126784-1.C: New test.
> > > > * g++.target/i386/pr126784-2.C: Likewise.
> > > > * gcc.target/i386/pr126784-1.c: Likewise.
> > > > * gcc.target/i386/pr126784-2.c: Likewise.
> > > > * gcc.target/i386/pr126788-1.c: Likewise.
> > > >
> > > > --
> > > > H.J.
> >
> >
> >
> > --
> > H.J.