On 9/16/26 9:16 AM, [email protected] wrote:
From: Kyrylo Tkachov <[email protected]>

Unsigned saturating truncation can form its sign mask from ~X instead of -X.
This avoids negating the minimum signed value.

For negative X, ~X is nonnegative and its top-bit shift is zero.  For positive
X above the result range, ~X is negative and its top-bit shift is all ones.
Recognize this form.  Keep the unsigned range comparison because a signed
comparison does not clamp negative inputs.

With AArch64 -O2 -march=armv8-a -fopenmp-simd:

before:

complement_clip4:
        ldr     q31, [x1]
        movi    v30.4s, 0xff, msl 8
        not     v29.16b, v31.16b
        cmhi    v30.4s, v31.4s, v30.4s
        cmlt    v29.4s, v29.4s, #0
        bif     v29.16b, v31.16b, v30.16b
        xtn     v29.4h, v29.4s
        str     d29, [x0]
        ret

after:

complement_clip4:
        ldr     q31, [x1]
        movi    v30.4s, 0
        smax    v30.4s, v31.4s, v30.4s
        uqxtn   v30.4h, v30.4s
        str     d30, [x0]
        ret

Tests cover both widths, extrema, bounds, LTO, and a signed-comparison
counterexample.  The AArch64 test covers both valid forms.

Bootstrapped and tested on aarch64-none-linux-gnu.

Ok for trunk?

Changes since v3:
- Rebase after the constant-clamp matcher changes.

gcc/ChangeLog:

        * match-sat-alu.pd (unsigned_integer_narrow_clip): Add the complement
        form.

gcc/testsuite/ChangeLog:

        * gcc.dg/sat-trunc-signed-cmp-2.c: New test.
        * gcc.dg/vect/vect-sat-trunc-complement-1.c: Likewise.
        * gcc.target/aarch64/vect-sat-trunc-complement-1.c: Likewise.
OK
jeff

Reply via email to