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

--- Comment #3 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Roger Sayle <[email protected]>:

https://gcc.gnu.org/g:67ec3f5215298dd7f3177ed16c10c84392db8bb6

commit r17-3260-g67ec3f5215298dd7f3177ed16c10c84392db8bb6
Author: Roger Sayle <[email protected]>
Date:   Thu Aug 13 16:55:40 2026 +0200

    PR rtl-optimization/126315: Failure of gcc.target/arm/pr42879.c on armv7-a.

    My recent patch related to PR tree-optimization/123236
    triggers the testsuite failure of gcc.target/arm/pr42879.c
    which is a missed optimization on ARM with -mthumb where we
    now fail to emit the (shorter) lsls instruction.

    I believe this change simply exposes an underlying problem/wart
    in combine related to WORD_REGISTER_OPERATIONS, that has been
    present in the compiler for decades.

    My opinion is that on WORD_REGISTER_OPERATIONS targets, this
    transformation in combine can result in some very dubious RTL
    (containing a paradoxical SUBREG of an AND binary operator).
    As a result, thumb.md (reasonably) fails to match:

    Trying 11 -> 12:
       11: r102:SI=r98:QI#0&0x1
          REG_DEAD r98:QI
       12: cc:CC=cmp(r102:SI,0)
          REG_DEAD r102:SI
    Failed to match this instruction:
    (set (reg:CC 80 cc)
        (compare:CC (subreg:SI (and:QI (reg:QI 98 [ *p_6(D) ])
                    (const_int 1 [0x1])) 0)
            (const_int 0 [0])))

    One approach might be for WORD_REGISTER_OPERATIONS targets to
    match this poorly defined pseudo-canonical RTL.  Should the
    compare assume the paradoxical SUBREG is zero extended, sign
    extended or junk?  Clearly the results of the comparison do
    depend upon the high bits.

    Fortunately, simply disabling the offending transformation fixes
    this issue, with combine proposing very reasonable RTL, which is
    already matched by ARM's thumb.md:

    Trying 11 -> 12:
       11: r102:SI=r98:QI#0&0x1
          REG_DEAD r98:QI
       12: cc:CC=cmp(r102:SI,0)
          REG_DEAD r102:SI
    Successfully matched this instruction:
    (set (reg:CC_NZ 80 cc)
        (compare:CC_NZ (zero_extract:SI (subreg:SI (reg:QI 98 [ *p_6(D) ]) 0)
                (const_int 1 [0x1])
                (const_int 0 [0]))
            (const_int 0 [0])))
    Successfully matched this instruction:
    (set (pc)
        (if_then_else (ne (reg:CC_NZ 80 cc)
                (const_int 0 [0]))
            (label_ref 18)
            (pc)))
    allowing combination of insns 11 and 12
    original costs 4 + 4 = 24
    replacement cost 20
    deferring deletion of insn with uid = 11.
    modifying other_insn    13: pc={(cc:CC_NZ!=0)?L18:pc}
          REG_DEAD cc:CC
          REG_BR_PROB 548896825
    deferring rescan insn with uid = 13.
    modifying insn i3    12: cc:CC_NZ=cmp(zero_extract(r98:QI#0,0x1,0),0)
          REG_DEAD r98:QI
    deferring rescan insn with uid = 12.

    2026-08-13  Roger Sayle  <[email protected]>

    gcc/ChangeLog
            PR rtl-optimization/126315
            * combine.cc (simplify_comparison) <case AND>: Delete
            transformation that changed (AND (SUBREG x) C) into the
            non-canonical (SUBREG (AND x C)).

Reply via email to