Hi Dominic,
> On 9 Sep 2026, at 23:29, Dominic P <[email protected]> wrote:
>
> The vectoriser expands the signed-source clip idiom recognised by
> unsigned_integer_narrow_clip as MAX_EXPR <0, x> feeding IFN_SAT_TRUNC,
> which lands as smax + uqxtn. sqxtun does both in one instruction.
> Combine offers the merged form because the zero vector carries a
> REG_EQUAL note, so only a define_insn is needed.
>
> This completes the smax + uqxtn pair that 10/13 of the pending
> "Saturating arithmetic matching improvements" series leaves
> (patchwork 142865).
>
> Regression tested on aarch64-linux-gnu under qemu (aarch64.exp,
> vect.exp); bootstrapped as part of the tree on x86_64.
>
> Assisted-by: Claude Opus 5 (Anthropic)
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64-simd.md
> (*aarch64_sqmovun<mode>_smax<vczle><vczbe>): New pattern.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/vect-sat-trunc-3.c: New test.
>
> Signed-off-by: Dominic P <[email protected]>
> ---
> gcc/config/aarch64/aarch64-simd.md | 11 +++++++++++
> .../gcc.target/aarch64/vect-sat-trunc-3.c | 17 +++++++++++++++++
> 2 files changed, 28 insertions(+)
> create mode 100644 gcc/testsuite/gcc.target/aarch64/vect-sat-trunc-3.c
>
> diff --git a/gcc/config/aarch64/aarch64-simd.md
> b/gcc/config/aarch64/aarch64-simd.md
> index 12dcabb7a15..4fa0e85e962 100644
> --- a/gcc/config/aarch64/aarch64-simd.md
> +++ b/gcc/config/aarch64/aarch64-simd.md
> @@ -6265,6 +6265,17 @@
> [(set_attr "type" "neon_sat_shift_imm_narrow_q")]
> )
>
> +;; MAX_EXPR <0, x> feeding IFN_SAT_TRUNC, as the vectoriser builds it.
> +(define_insn "*aarch64_sqmovun<mode>_smax<vczle><vczbe>"
> + [(set (match_operand:<VNARROWQ> 0 "register_operand" "=w")
> + (us_truncate:<VNARROWQ>
> + (smax:VQN (match_operand:VQN 1 "register_operand" "w")
> + (match_operand:VQN 2 "aarch64_simd_or_scalar_imm_zero"))))]
> + "TARGET_SIMD"
> + "sqxtun\\t%<vn2>0<Vmntype>, %<v>1<Vmtype>"
> + [(set_attr "type" "neon_sat_shift_imm_narrow_q")]
> +)
I think the correct (and larger) thing that needs fixing is that the existing
RTL patterns for sqxtun: aarch64_sqmovun<mode> and
*aarch64_sqmovun<mode>_insn<vczle><vczbe> are expressed with more complex RTL
than needed: your proposed us_truncate+smax-0 should be the RTL directly
matched by these instructions and the form they currently match:
[(set (match_operand:<VNARROWQ> 0 "register_operand" "=w”)
(truncate:<VNARROWQ>
(smin:SD_HSDI
(smax:SD_HSDI (match_operand:SD_HSDI 1 "register_operand" "w”)
(const_int 0))
(const_int <half_mask>))))]
Should simplify to the us_truncate+smax form through simplify-rtx.
Thanks,
Kyrill
> +
> (define_expand "aarch64_sqmovun<mode>"
> [(set (match_operand:<VNARROWQ> 0 "register_operand" "=w")
> (truncate:<VNARROWQ>
> diff --git a/gcc/testsuite/gcc.target/aarch64/vect-sat-trunc-3.c
> b/gcc/testsuite/gcc.target/aarch64/vect-sat-trunc-3.c
> new file mode 100644
> index 00000000000..56a4ba209fb
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/vect-sat-trunc-3.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -march=armv8-a" } */
> +
> +typedef __UINT16_TYPE__ u16;
> +
> +void
> +clip_u16 (u16 *__restrict r, const int *__restrict x, int n)
> +{
> + for (int i = 0; i < n; i++)
> + {
> + int v = x[i] | 1;
> + r[i] = (unsigned int) v > 65535u ? ((-v) >> 31) : v;
> + }
> +}
> +
> +/* { dg-final { scan-assembler {\tsqxtun\tv[0-9]+\.4h, v[0-9]+\.4s} } } */
> +/* { dg-final { scan-assembler-not {\tuqxtn\tv[0-9]+\.4h, v[0-9]+\.4s} } } */
> --
> 2.55.0
>