https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111609

--- Comment #2 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The trunk branch has been updated by Richard Earnshaw <[email protected]>:

https://gcc.gnu.org/g:93ac5163b5d02c2dfde88c3ec7b1f366caab9b45

commit r17-3926-g93ac5163b5d02c2dfde88c3ec7b1f366caab9b45
Author: Dominic P <[email protected]>
Date:   Sun Aug 2 11:56:05 2026 +0100

    arm: fix vshll_n intrinsics with boundary shift [PR111609]

    The NEON widening-shift-left-long intrinsics (vshll_n_s8/s16/s32 and
    vshll_n_u8/u16/u32) accept a shift amount in the range [0, element_size].
    The bounds check in neon_vshll<sup>_n<mode> already permits a shift of
    zero (its stale comment said "0 < imm" while the code implements
    "0 <= imm"), but it then emitted a literal "vshll.<sz> qD, dN, #0".

    The VSHLL encoding cannot represent a shift of zero -- valid immediates
    are 1..element_size -- so the assembler rejected the output with
    "Error: immediate value out of range".

    The ACLE semantics of a widening shift-left by zero are exactly those of
    a widening move, so divert the imm == 0 case to VMOVL, which is the
    correct and encodable instruction.  This turns previously-broken valid
    ACLE code into working code (better QoI than rejecting it).  Nonzero
    shifts, including a shift by the element size, are unchanged.

    A related issue exists when the shift size is equal to the element size.
    For these cases the mnemonic should use a signless form (i8, i16, i32).

    Assisted-by: Claude Opus 5 (Anthropic)

            PR target/111609

    gcc/ChangeLog:

            * config/arm/neon.md (neon_vshll<sup>_n<mode>): Emit vmovl for a
            shift of zero.  Use signless form when the shift amount == element
            size.

    gcc/testsuite/ChangeLog:

            * gcc.target/arm/pr111609.c: New test.

    Signed-off-by: Dominic P <[email protected]>
    Co-authored-by: Richard Earnshaw <[email protected]>

Reply via email to