The simultaneous use of setjmp/longjmp and alloca isn't an easy matter. The crux of the problem is that the stack pointer is saved into the setjmp buffer upon its creation. If a dynamic stack allocation occurs afterward, changing the stack pointer, does the value saved in the buffer need to be updated?
The answer is, it depends. The default implementations of SJLJ exceptions and of the __builtin_setjmp/__builtin_longjmp support don't update it. This is correct in some situations but not in others (VLAs), see PR middle-end/19774 and http://gcc.gnu.org/ml/gcc-patches/2007-03/msg00946.html for a patch. In Ada, we implement our SJLJ exception scheme "manually", i.e. part in the front-end and the rest piggybacked on __builtin_setjmp/__builtin_longjmp. Since we have only VLAs (no alloca in particular), we need to update it in all cases and Richard K. devised a special built-in function to do so: http://gcc.gnu.org/ml/gcc-patches/2004-04/msg01739.html On top of that, SPARC adds its own twist as it is the only architecture to define SETJMP_VIA_SAVE_AREA. On the SPARC, we don't really use the setjmp buffer but instead reuse the register window save area present in all frames. But there is a hitch: when a dynamic stack allocation occurs, we need to both preserve the old save area for setjmp and pre-save the important registers in case the stack pointer isn't updated, and pre-save the important registers into the new area in case the stack pointer is updated. That's why SPARC is the only architecture to define the undocumented 'setjmp' pattern, which is only invoked by BUILT_IN_UPDATE_SETJMP_BUF and consequently only used in Ada. It turns out that this 'setjmp' pattern works neither in 64-bit mode nor in PIC mode, very likely since the very beginning. We don't test ACATS in SJLJ+PIC or 64-bit SJLJ mode on the SPARC at AdaCore so this has gone unnoticed. Fixed thusly, bootstrapped/regtested on SPARC/Solaris and SPARC64/Solaris, applied on the mainline and 4.6/4.5/4.4 branches. SPARC maintainers, any objection to me eliminating this SETJMP_VIA_SAVE_AREA kludge? This would make it possible to have a shared implementation with the flat mode and remove specific support in a few locations. Even IA-64 does things the canonical way here. 2011-05-21 Eric Botcazou <ebotca...@adacore.com> * config/sparc/sparc.md (setjmp): Handle PIC mode and use the hard frame pointer. -- Eric Botcazou
Index: config/sparc/sparc.md =================================================================== --- config/sparc/sparc.md (revision 173993) +++ config/sparc/sparc.md (working copy) @@ -6507,8 +6559,8 @@ (define_insn "goto_handler_and_restore" (const_int 4)))]) ;; For __builtin_setjmp we need to flush register windows iff the function -;; calls alloca as well, because otherwise the register window might be -;; saved after %sp adjustment and thus setjmp would crash +;; calls alloca as well, because otherwise the current register window might +;; be saved after the %sp adjustment and thus setjmp would crash. (define_expand "builtin_setjmp_setup" [(match_operand 0 "register_operand" "r")] "" @@ -6547,19 +6599,26 @@ (define_insn "do_builtin_setjmp_setup" (eq_attr "pic" "true") (const_int 4)] (const_int 3)))]) -;; Pattern for use after a setjmp to store FP and the return register -;; into the stack area. +;; Pattern for use after a setjmp to store registers into the save area. (define_expand "setjmp" [(const_int 0)] "" { rtx mem; - + + if (flag_pic) + { + mem = gen_rtx_MEM (Pmode, + plus_constant (stack_pointer_rtx, + SPARC_STACK_BIAS + 7 * UNITS_PER_WORD)); + emit_insn (gen_rtx_SET (VOIDmode, mem, pic_offset_table_rtx)); + } + mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS + 14 * UNITS_PER_WORD)); - emit_insn (gen_rtx_SET (VOIDmode, mem, frame_pointer_rtx)); + emit_insn (gen_rtx_SET (VOIDmode, mem, hard_frame_pointer_rtx)); mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,