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.