This is seen on the version of avr-gcc 4.3.3 that gets built by the script that comes with FemtoOS 0.88. The program performs simple arithmatic and logical operations on a global variable, and store the result in register R30:R31. If the program is compiled with "avr-gcc -mmcu=atmega128 -O0", the final result is 00. On the other hand, if the program is compiled with "avr-gcc -mmcu=atmega128 -O1", the final result is 0xFF. Compiling at O2 gives me 0xFF too. Obviously, avr-gcc compiled the program wrong at one of the these optimization levels. This bug is observed in avr studio 4.15.
Created attachment 17400 [details] mis-calculated program
Confirmed with gcc 4.3.2.
Please try using gcc 4.4 (HEAD). Anatoly Sokolov (AVR port maintainer) has indicated to me that he does not see this bug when using HEAD/4.4.
*** Bug 39635 has been marked as a duplicate of this bug. ***
Adding additional version numbers in the known-to-fail field from comment in duplicate bug #39635. Still waiting to hear if bug is present in 4.4.
Confirmed with gcc 4.4.0. Using switch -O0 with avr-gcc 4.4.0 (-mmcu=atmega128) gave the result 0 while -O1 gave 0xFF
Created attachment 21547 [details] Reduced testcase Reduced testcase to reproduce the bug.
When -O2 is enabled result is 0xFF (255) which is incorrect. The code generated for the following shift operation: 13: return (left << right); +000000AB: C004 RJMP PC+0x0005 Relative jump +000000AC: 0F22 LSL R18 Logical Shift Left +000000AD: 1F33 ROL R19 Rotate Left Through Carry +000000AE: 1F44 ROL R20 Rotate Left Through Carry +000000AF: 1F55 ROL R21 Rotate Left Through Carry +000000B0: 952A DEC R18 Decrement +000000B1: F7D2 BRPL PC-0x05 Branch if plus 19: g_6= func_1 (g_6, g_6); +000000B2: 93200100 STS 0x0100,R18 Store direct to data space 'left' is stored in registers R21:R20:R19:R18 as it is typecasted to uint32_t type while 'right' is stored in R18. Because of shift logic, R18 becomes 0xFF in first iteration which is then stored.
I already generated a simple testcase (although different)in http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39635. The comments from Andy in the linked report might be worth reproducing here
The problem arises from the following insns: *ashlqi3 ashlhi3 ashlsi3 ashrqi3 ashrhi3 ashrsi3 *lshrqi3 lshrhi3 lshrsi3 For variable shifts the first constraint alternative is "=r,0,r" avr.c:out_shift_with_cnt() reads else if (register_operand (operands[2], QImode)) { if (reg_unused_after (insn, operands[2])) op[3] = op[2]; else { op[3] = tmp_reg_rtx; if (!len) strcat (str, (AS2 (mov,%3,%2) CR_TAB)); } } so that in the very rare, pathological case of op0 = op1 = op2 and op2 is unused after the insn, wrong code gets generated. Fix is: if (reg_unused_after (insn, operands[2]) && !reg_overlap_mentioned_p (operands[0], operands[2])) or something like that.
Created attachment 24814 [details] Minimal testcase Minimal testcase that also miscompiles for newer versions of the compiler like 4.5.2 or 4.6.1. Compiles with -Os to shift: rjmp 2f 1: lsl r24 rol r25 2: dec r24 brpl 1b ret
Author: gjl Date: Mon Jul 25 15:41:55 2011 New Revision: 176756 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=176756 Log: PR target/39386 * config/avr/avr.c (out_shift_with_cnt): Use tmp_reg as shift counter for x << x and x >> x shifts. Modified: trunk/gcc/ChangeLog trunk/gcc/config/avr/avr.c
Author: gjl Date: Mon Jul 25 15:45:47 2011 New Revision: 176757 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=176757 Log: PR target/39386 Backport from mainline r176756 2011-07-25 Georg-Johann Lay * config/avr/avr.c (out_shift_with_cnt): Use tmp_reg as shift counter for x << x and x >> x shifts. Modified: branches/gcc-4_6-branch/gcc/ChangeLog branches/gcc-4_6-branch/gcc/config/avr/avr.c
Closed as FIXED.