On 5/4/2026 7:16 AM, Daniel Henrique Barboza wrote:
[ Snip]

If we follow this same logic, for the example I talked about earlier for
a 64 bit 'long' var:

 _Bool f1(long a)
 {
     long b = a << 4;
     return b == -128;
 }
So with the recent patch to the RISC-V port we won't regress if this patch is applied.  However, as I feared after looking at things in depth yesterday, we will regress cris and likely other targets.

Before this change we'd get something like this on cris-elf:

        lslq 4,$r10
        cmps.b -128,$r10
        ret
        seq $r10

Guessing that seq is in a delay slot, so we should conceptually think of it as executing before the ret.    Reasonable looking code.  After the patch for 124019 we'd generate this instead:

        lslq 4,$r10     ;# 26   [c=4 l=2] ashlsi3
        lsrq 4,$r10     ;# 27   [c=4 l=2]  lshrsi3
        cmp.d 268435448,$r10    ;# 18   [c=8 l=2]  *cmpsicc/4
        ret             ;# 22   [c=0 l=2]  *return_expanded
        seq $r10                ;# 19   [c=4 l=2]  *seqcc
That's worse on at least one and possibly two axis.  THere's the additional shift and I suspect that cmp.d is slower and/or encodes worse than the cmp.b we generated before.

To recover on cris we'd need to match this kind of pattern:

        (set (reg/i:QI 10 r10)
            (eq:QI (and:SI (reg:SI 33 [ a ])
                    (const_int 268435455 [0xfffffff]))
                (const_int 268435448 [0xffffff8])))
        (clobber (reg:CC 19 ccr))

The trick being if we shift that second constant by 4 positions left, the result is an easily encodable -128 and shifting reg:SI 33 left by 4 would cancel out insn 27.  But more importantly I suspect we'd end up playing wack-a-mole  on a port-by-port basis.  So while we've made RISC-V immune to this problem and I can see a path to fix cris, I suspect we'd end up having to fix a ton of ports.

So I think the transformation we want probably can't be done in gimple, at least not without testing and fixing many of the 30+ ISA targets we support.

So if we return to thinking about this as an RTL transformation I keep thinking we'll want to focus on this insn:

Trying 6, 8, 12 -> 13:
    6: r139:DI=r148:DI<<0x4
      REG_DEAD r148:DI
    8: r141:DI=sign_extend(r139:DI#0)
      REG_DEAD r139:DI
   12: r145:DI=r141:DI+0x80
      REG_DEAD r141:DI
   13: r144:DI=r145:DI==0
      REG_DEAD r145:DI
Failed to match this instruction:
(set (reg:DI 144)
    (eq:DI (subreg:QI (ashift:DI (reg:DI 148 [ a ])
                (const_int 4 [0x4])) 0)
        (const_int -128 [0xffffffffffffff80])))

We'd have to implement this as a 4->3 splitter.  We'd be taking advantage of the fact that we've got a subreg:QI wrapping one operand, so the bits outside QI don't matter.  So we could andi+addi+seq.  The mask would be 0xf since only the low 4 bits matter and the addi constant would be 8.

I don't like the define_insn_and_split, but I don't see anything better.

Something like this:

;; So the idea here is to realize that with a single insn we
;; can mask off all the relevant bits in the source operand.
;; A second insn generates zero/non-zero
;; The third and final insn canonicalizes that result to 0/1.
;;
;; There's probably some HImode cases we could handle too.  I haven't
;; thought hard about them.
(define_insn_and_split ""
  [(set (match_operand:X 0 "register_operand" "=r")
        (any_eq:X (subreg:QI
                   (ashift:X (match_operand:X 1 "register_operand" "r")
                             (match_operand 2 "const_int_operand")) 0)
                  (match_operand 3 "const_int_operand")))]
  "(INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 8
    && INTVAL (operands[3]) >= -128 && INTVAL (operands[2]) <= 127
    && (INTVAL (operands[3])
        & ((HOST_WIDE_INT_1U << INTVAL (operands[2])) - 1)) == 0)"
  "#"
  "&& 1"
  [(set (match_dup 0) (and:X (match_dup 1) (match_dup 2)))
   (set (match_dup 0) (plus:X (match_dup 0) (match_dup 3)))
   (set (match_dup 0) (any_eq:X (match_dup 0) (const_int 0)))]
{
  operands[3] = GEN_INT (-(INTVAL (operands[3]) >> INTVAL (operands[2])));
  operands[2] = GEN_INT (0xff >> INTVAL (operands[2]));
}
  [(set_attr "type" "slt")
   (set_attr "mode" "<X:MODE>")])

Jeff




Reply via email to