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

            Bug ID: 71676
           Summary: [avr] casesi won't handle switch values larger than 16
                    bits
           Product: gcc
           Version: 5.2.1
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gjl at gcc dot gnu.org
  Target Milestone: ---
            Target: avr

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

This is a funny wrong code bug that is present since the avr backend has been
added to GCC in r31935.  casesi reads

https://gcc.gnu.org/viewcvs/gcc/trunk/gcc/config/avr/avr.md?view=markup&pathrev=31935#l1760

(define_expand "casesi"
  [(parallel [(set (match_dup 6)
                   (minus:HI (subreg:HI (match_operand:SI 0 "register_operand"
"") 0)
                             (match_operand:HI 1 "register_operand" "")))
              (clobber (scratch:QI))])
   (parallel [(set (cc0)
                   (compare (match_dup 6)
                            (match_operand:HI 2 "register_operand" "")))
              (clobber (match_scratch:QI 9 ""))])
   ...

which means that switch / case won't handle large values correctly provided
casesi is used.

The following code shows the problem.  Compile with

$ avr-gcc -mmcu=atmega128 bug-casesi.c -save-temps -dp -Os

volatile unsigned char y;

__attribute__((noinline,noclone))
unsigned char foo (unsigned long x) 
{
    switch (x)
    {
        case 0: y = 67; break;
        case 1: y = 20; break;
        case 2: y = 109; break;
        case 3: y = 33; break;
        case 4: y = 44; break;
        case 5: y = 37; break;
        case 6: y = 10; break;
        case 7: y = 98; break;
    }
    return y;
}

int main (void)
{
    if (0 != foo (7L + 0x10000L))
        __builtin_abort();
    return 0;
}


As casesi takes HImode SUBREG of x, only the lower 16 bits of x (R22 and R23)
are used to determine whether the switch has to be entered or not.  avr-gcc-5.2
generates:

foo:
    cpi r22,8                ;  9   *cmphi/6
    cpc r23,__zero_reg__
    brsh .L2                 ;  10  branch
    movw r30,r22             ;  91  *movhi/1
    subi r30,lo8(-(gs(.L4))) ;  11  *addhi3/2
    sbci r31,hi8(-(gs(.L4)))
    jmp __tablejump2__       ;  12  *tablejump/3

Hence 0x10007 will be treated the same way as 0x7.

Reply via email to