[gcc r17-3260] PR rtl-optimization/126315: Failure of gcc.target/arm/pr42879.c on armv7-a.
Roger Sayle via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[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)). Diff: --- gcc/combine.cc | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/gcc/combine.cc b/gcc/combine.cc index 6ee3c1a07cdf..743026317ce4 100644 --- a/gcc/combine.cc +++ b/gcc/combine.cc @@ -12872,50 +12872,6 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) continue; } - /* If this is (and:M1 (subreg:M1 X:M2 0) (const_int C1)) where C1 - fits in both M1 and M2 and the SUBREG is either paradoxical - or represents the low part, permute the SUBREG and the AND - and try again. */ - if (GET_CODE (XEXP (op0, 0)) == SUBREG - && CONST_INT_P (XEXP (op0, 1))) - { - unsigned HOST_WIDE_INT c1 = INTVAL (XEXP (op0, 1)); - /* Require an integral mode, to avoid creating something like - (AND:SF ...). */ - if ((is_a <scalar_int_mode> - (GET_MODE (SUBREG_REG (XEXP (op0, 0))), &tmode)) - /* It is unsafe to commute the AND into the SUBREG if the - SUBREG is paradoxical and WORD_REGISTER_OPERATIONS is - not defined. As originally written the upper bits - have a defined value due to the AND operation. - However, if we commute the AND inside the SUBREG then - they no longer have defined values and the meaning of - the code has been changed. - Also C1 should not change value in the smaller mode, - see PR67028 (a positive C1 can become negative in the - smaller mode, so that the AND does no longer mask the - upper bits). */ - && ((WORD_REGISTER_OPERATIONS - && mode_width > GET_MODE_PRECISION (tmode) - && mode_width <= BITS_PER_WORD - && trunc_int_for_mode (c1, tmode) == (HOST_WIDE_INT) c1) - || (mode_width <= GET_MODE_PRECISION (tmode) - && subreg_lowpart_p (XEXP (op0, 0)))) - && mode_width <= HOST_BITS_PER_WIDE_INT - && HWI_COMPUTABLE_MODE_P (tmode) - && (c1 & ~mask) == 0 - && (c1 & ~GET_MODE_MASK (tmode)) == 0 - && c1 != mask - && c1 != GET_MODE_MASK (tmode)) - { - op0 = simplify_gen_binary (AND, tmode, - SUBREG_REG (XEXP (op0, 0)), - gen_int_mode (c1, tmode)); - op0 = gen_lowpart (mode, op0); - continue; - } - } - /* Convert (ne (and (not X) 1) 0) to (eq (and X 1) 0). */ if (const_op == 0 && equality_comparison_p && XEXP (op0, 1) == const1_rtx