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

            Bug ID: 127404
           Summary: [avr] missed insn combine transformation (subreg
                    related?)
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gjl at gcc dot gnu.org
  Target Milestone: ---

Created attachment 65593
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65593&action=edit
x.c: C test case

int val;
long i32;
long volatile v32;
long f32 (void);

void func_1 (void)
{
    int i = f32();
    if (i & 1)
        val = i;
}

void func_2 (void)
{
    int i = v32;
    if (i & 1)
        val = i;
}

void func_3 (void)
{
    int i = i32;
    if (i & 1)
        val = i;
}

$ avr-gcc -mmcu=atmega128 -S x.c -Os -dp -da 

In this test case, the expected code for the bit test is a bit-test-and-skip
instruction, which is actually generated for func_3:

        sbrs r24,0       ;  24  [c=4 l=2]  *sbrx_branchhi
        rjmp .L13       

In func_1 and func_2 however, combine fails to find this and the outcome is a
code that requires 2 extra registers and needs 5 instructions, even though the
very test code is exactly the same:

        mov r18,r24      ;  38  [c=4 l=2]  *andqi3/3
        andi r18,1<<0
        ldi r19,0                ;  39  [c=4 l=1]  movqi_insn/0
        or r18,r19       ;  30  [c=8 l=1]  cmphi3/1
        breq .L7                 ;  31  [c=4 l=1]  branch

The combine dump shows for func_3:

Trying 7 -> 8:
    7: {r47:HI=r45:HI&0x1;clobber scratch;}
    8: {pc={(r47:HI==0)?L13:pc};clobber scratch;}
      REG_DEAD r47:HI
      REG_BR_PROB 536870913
Failed to match this instruction:
...
Successfully matched this instruction:
(set (pc)
    (if_then_else (eq (zero_extract:HI (reg/v:HI 45 [ i ])
                (const_int 1 [0x1])
                (const_int 0 [0]))
            (const_int 0 [0]))
        (label_ref:HI 13)
        (pc)))
allowing combination of insns 7 and 8
original costs 8 + 12 = 20
replacement cost 6

with insns:

(insn 7 6 8 2 (parallel [
            (set (reg:HI 47 [ _2 ])
                (and:HI (reg/v:HI 45 [ i ])
                    (const_int 1 [0x1])))
            (clobber (scratch:QI))
        ]) "x.c":23:11 625 {andhi3}
     (nil))
(jump_insn 8 7 9 2 (parallel [
            (set (pc)
                (if_then_else (eq (reg:HI 47 [ _2 ])
                        (const_int 0 [0]))
                    (label_ref:HI 13)
                    (pc)))
            (clobber (scratch:QI))
        ]) "x.c":23:8 892 {cbranchhi4_insn}

In func_1 and func_2 however, the AND insn reads

(insn 8 6 9 2 (parallel [
            (set (reg:HI 46 [ _2 ])
                (and:HI (subreg:HI (reg:SI 43 [ _1 ]) 0)
                    (const_int 1 [0x1])))
            (clobber (scratch:QI))
        ]) "x.c":9:11 625 {andhi3}
     (nil))

Shouldn't it be possible to combine that, too?

Target: avr
Configured with: .../configure --target=avr --disable-nls --with-dwarf2
--with-gnu-as --with-gnu-ld --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 17.0.0 20260912 (experimental) (GCC)

Reply via email to