"* return i960_output_ret_insn (insn);"
[(set_attr "type" "branch")])
+;; A return instruction. Used only by nonlocal_goto to change the
+;; stack pointer, frame pointer, previous frame pointer and the return
+;; instruction pointer.
+(define_insn "ret"
+ [(use (reg:SI 16))
+ (unspec_volatile [(const_int 0)] 3)]
+ ""
+ "ret"
+ [(set_attr "type" "branch")
+ (set_attr "length" "1")])
+
+(define_expand "nonlocal_goto"
+ [(match_operand:SI 0 "" "")
+ (match_operand:SI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" "")
+ (match_operand:SI 3 "general_operand" "")]
+ ""
+ "
+{
+ rtx fp = operands[1];
+ rtx new_pc = operands[3];
+ rtx stack = operands[2];
+ rtx val = operands[0];
+
+ /* This code isn't sufficient to make nonlocal_gotos for nested
+ functions to work fully. Here we assume that the passed frame
+ pointer is a real hard frame pointer, not a
+ virtual_stack_vars_rtx type of frame. */
+
+ /* We must restore the stack pointer, frame pointer, previous frame
+ pointer and the return instruction pointer. Since the ret
+ instruction does all this for us with one instruction, we arrange
+ everything so that ret will do everything we need done. */
+
+ if (GET_CODE (fp) != REG)
+ fp = force_reg (Pmode, fp);
+ if (GET_CODE (val) != REG)
+ val = force_reg (Pmode, val);
+ if (GET_CODE (new_pc) != REG)
+ new_pc = force_reg (Pmode, new_pc);
+
+
+ /* First, we must flush the register windows, so that we can modify
+ the saved local registers on the stack directly and because we
+ are going to change the previous frame pointer. */
+
+ emit_insn (gen_flush_register_windows ());
+
+ /* Next, we put the address that we want to transfer to, into the
+ saved $rip value on the stack. Once we ret below, that value
+ will be loaded into the pc (IP). */
+
+ emit_move_insn (gen_rtx (MEM, SImode,
+ plus_constant (fp, 8)),
+ new_pc);
+
+ /* Next, we put the value into the static chain register's save
+ area on the stack. After the ret below, this will be loaded into
+ r3 (the static chain). */
+
+ emit_move_insn (gen_rtx (MEM, SImode,
+ plus_constant (fp, 12)),
+ val);
+
+ /* We now load pfp (the previous frame pointer) with the value that
+ we want fp to be. */
+
+ emit_move_insn (gen_rtx (REG, SImode, 16), fp);
+
+ /* And finally, we can now just ret to get all the values saved
+ above into all the right registers, and also, all the local
+ register that were in use in the function, are restored from
+ their saved values (from the call instruction) on the stack
+ because we are very careful to ret from the exact save area in
+ use during the original call. */
+
+ emit_insn (gen_ret ());
+ emit_barrier ();
+ DONE;
+}")
+
+;; Special insn to flush register windows.
+(define_insn "flush_register_windows"
+ [(unspec_volatile [(const_int 0)] 1)]
+ ""
+ "flushreg"
+ [(set_attr "type" "misc")
+ (set_attr "length" "1")])
+
(define_insn "nop"
[(const_int 0)]
""
address of the stack word that points to the previous frame.
@findex SETUP_FRAME_ADDRESSES
-@item SETUP_FRAME_ADDRESSES ()
+@item SETUP_FRAME_ADDRESSES
If defined, a C expression that produces the machine-specific code to
setup the stack so that arbitrary frames can be accessed. For example,
on the Sparc, we must flush all of the register windows to the stack
-before we can access arbitrary stack frames.
-This macro will seldom need to be defined.
+before we can access arbitrary stack frames. You will seldom need to
+define this macro.
+
+@findex BUILTIN_SETJMP_FRAME_VALUE
+@item BUILTIN_SETJMP_FRAME_VALUE
+If defined, a C expression that contains an rtx that is used to store
+the address of the current frame into the built in @code{setjmp} buffer.
+The default value, @code{virtual_stack_vars_rtx}, is correct for most
+machines. One reason you may need to define this macro is if
+@code{hard_frame_pointer_rtx} is the appropriate value on your machine.
@findex RETURN_ADDR_RTX
@item RETURN_ADDR_RTX (@var{count}, @var{frameaddr})