The test case is gcc.c-torture/execute/built-in-setjmp.c. The __builtin_setjmp stores Y+1 in the setjmp buffer. With -O0 the first instruction after the jmp does a "sbiw r28, 1" that restores the original value, but for some reason, with higher optimization levels, this instruction is optimized away, leaving R28 pointing to the wrong address by one. The __builtin_setjmp code: if (__builtin_setjmp (buf)) 16a: ce 01 movw r24, r28 16c: 01 96 adiw r24, 0x01 ; 1 Notice the increment here, before storing R28 16e: 90 93 07 01 sts 0x0107, r25 172: 80 93 06 01 sts 0x0106, r24 176: 8f ee ldi r24, 0xEF ; 239 178: 90 e0 ldi r25, 0x00 ; 0 17a: 90 93 09 01 sts 0x0109, r25 17e: 80 93 08 01 sts 0x0108, r24 182: ed b7 in r30, 0x3d ; 61 184: fe b7 in r31, 0x3e ; 62 186: f0 93 0b 01 sts 0x010B, r31 18a: e0 93 0a 01 sts 0x010A, r30 The __builtin_longjmp code: __builtin_longjmp (buf, 1); 10c: e0 91 08 01 lds r30, 0x0108 110: f0 91 09 01 lds r31, 0x0109 114: c0 91 06 01 lds r28, 0x0106 118: d0 91 07 01 lds r29, 0x0107 11c: 80 91 0a 01 lds r24, 0x010A 120: 90 91 0b 01 lds r25, 0x010B no decrement, R28 is used "as is".
Created attachment 15395 [details] Setjmp patch for AVR The attached patch is a fix for AVR target. MIPS does something similar to get around same issue. The real problem is with gcc builin setjmp receiver being removed by optimizers. Optimizers think that frame_pointer load in receiver is unneeded and remove it! The patch loads the frame pointer in the nonlocal_goto, making the receiver (where it jumps to) empty, so bad optimization cannot remove it. Additionally, it avoids the unnecessary arithmetic around frame pointer offsets. This patch was tested and the testcase passes. Further changes may be required in the future if AVR 24bit jumps are to be supported.
Subject: Bug 34879 Author: hutchinsonandy Date: Mon Jun 2 22:08:25 2008 New Revision: 136297 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=136297 Log: PR target/34879 * config/avr/avr.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Redefine. (avr_builtin_setjmp_frame_value): New function. * config/avr/avr.md (nonlocal_goto_receiver): Define. (nonlocal_goto): Define. Modified: trunk/gcc/ChangeLog trunk/gcc/config/avr/avr.c trunk/gcc/config/avr/avr.md
Fixed in 4.4.0.